diff --git a/apps/dhcp/dhcp.c b/apps/dhcp/dhcp.c index 9ea9b0605..a7d72943b 100644 --- a/apps/dhcp/dhcp.c +++ b/apps/dhcp/dhcp.c @@ -114,7 +114,7 @@ PROCESS_THREAD(dhcp_process, ev, data) CTK_WIDGET_FOCUS(&window, &getbutton); ctk_window_open(&window); - dhcpc_init(uip_ethaddr.addr, sizeof(uip_ethaddr.addr)); + dhcpc_init(uip_lladdr.addr, sizeof(uip_lladdr.addr)); while(1) { diff --git a/apps/email/email.c b/apps/email/email.c index 760155041..ae74e4e1b 100644 --- a/apps/email/email.c +++ b/apps/email/email.c @@ -191,8 +191,7 @@ applyconfig(void) addrptr = &addr; #if UIP_UDP if(uiplib_ipaddrconv(smtpserver, &addr) == 0) { - addrptr = resolv_lookup(smtpserver); - if(addrptr == NULL) { + if(resolv_lookup(smtpserver, &addrptr) != RESOLV_STATUS_CACHED) { resolv_query(smtpserver); ctk_label_set_text(&statuslabel, "Resolving host..."); return; @@ -334,7 +333,7 @@ PROCESS_THREAD(email_process, ev, data) #if UIP_UDP } else if(ev == resolv_event_found) { if(strcmp(data, smtpserver) == 0) { - if(resolv_lookup(smtpserver) != NULL) { + if(resolv_lookup(smtpserver, NULL) == RESOLV_STATUS_CACHED) { applyconfig(); ctk_label_set_text(&statuslabel, ""); } else { diff --git a/apps/ftp/ftp.c b/apps/ftp/ftp.c index 45f24df1e..b20499aee 100644 --- a/apps/ftp/ftp.c +++ b/apps/ftp/ftp.c @@ -434,7 +434,7 @@ PROCESS_THREAD(ftp_process, ev, data) } else if(ev == resolv_event_found) { /* Either found a hostname, or not. */ if((char *)data != NULL && - (ipaddrptr = resolv_lookup((char *)data)) != NULL) { + resolv_lookup((char *)data, &ipaddrptr) == RESOLV_STATUS_CACHED) { connection = ftpc_connect(ipaddrptr, UIP_HTONS(21)); show_statustext("Connecting to ", hostname); } else { @@ -508,8 +508,7 @@ PROCESS_THREAD(ftp_process, ev, data) ptractive = 1; #if UIP_UDP if(uiplib_ipaddrconv(hostname, &ipaddr) == 0) { - ipaddrptr = resolv_lookup(hostname); - if(ipaddrptr == NULL) { + if(resolv_lookup(hostname, &ipaddrptr) != RESOLV_STATUS_CACHED) { resolv_query(hostname); show_statustext("Resolving host ", hostname); break; diff --git a/apps/httpd-ws/httpd-ws.c b/apps/httpd-ws/httpd-ws.c index c28230897..1107e53cc 100644 --- a/apps/httpd-ws/httpd-ws.c +++ b/apps/httpd-ws/httpd-ws.c @@ -378,9 +378,7 @@ httpd_ws_request(char request_type, const char *host_ip, const char *host_hdr, ipaddr = &addr; if(uiplib_ipaddrconv(host_ip, &addr) == 0) { #if 0 && UIP_UDP - ipaddr = resolv_lookup(host_ip); - - if(ipaddr == NULL) { + if(resolv_lookup(host, &ipaddr) != RESOLV_STATUS_CACHED) { return NULL; } #else /* UIP_UDP */ diff --git a/apps/irc/irc.c b/apps/irc/irc.c index ba46a369f..733426944 100644 --- a/apps/irc/irc.c +++ b/apps/irc/irc.c @@ -246,8 +246,7 @@ PROCESS_THREAD(irc_process, ev, data) ipaddr = &serveraddr; #if UIP_UDP if(uiplib_ipaddrconv(server, &serveraddr) == 0) { - ipaddr = resolv_lookup(server); - if(ipaddr == NULL) { + if(resolv_lookup(server, &ipaddr) != RESOLV_STATUS_CACHED) { resolv_query(server); } else { uip_ipaddr_copy(&serveraddr, ipaddr); @@ -264,8 +263,7 @@ PROCESS_THREAD(irc_process, ev, data) #if UIP_UDP } else if(ev == resolv_event_found) { - ipaddr = resolv_lookup(server); - if(ipaddr == NULL) { + if(resolv_lookup(server, &ipaddr) != RESOLV_STATUS_CACHED) { ircc_text_output(&s, server, "hostname not found"); } else { uip_ipaddr_copy(&serveraddr, ipaddr); diff --git a/apps/shell/shell-irc.c b/apps/shell/shell-irc.c index 8dfd241f6..dc4ee2b30 100644 --- a/apps/shell/shell-irc.c +++ b/apps/shell/shell-irc.c @@ -157,7 +157,7 @@ PROCESS_THREAD(shell_irc_process, ev, data) } else if(ev == resolv_event_found) { /* Either found a hostname, or not. */ if((char *)data != NULL && - resolv_lookup((char *)data) != NULL) { + resolv_lookup((char *)data, &ipaddr) == RESOLV_STATUS_CACHED) { uip_ipaddr_copy(serveraddr, ipaddr); ircc_connect(&s, server, serveraddr, nick); } else { diff --git a/apps/shell/shell-ping.c b/apps/shell/shell-ping.c index 0fea8bb90..8f202d162 100644 --- a/apps/shell/shell-ping.c +++ b/apps/shell/shell-ping.c @@ -166,7 +166,7 @@ PROCESS_THREAD(shell_ping_process, ev, data) } else if(ev == resolv_event_found) { /* Either found a hostname, or not. */ if((char *)data != NULL && - resolv_lookup((char *)data) != NULL) { + resolv_lookup((char *)data, &ipaddr) == RESOLV_STATUS_CACHED) { uip_ipaddr_copy(serveraddr, ipaddr); telnet_connect(&s, server, serveraddr, nick); } else { diff --git a/apps/shell/shell-tcpsend.c b/apps/shell/shell-tcpsend.c index cd1be1411..923cda181 100644 --- a/apps/shell/shell-tcpsend.c +++ b/apps/shell/shell-tcpsend.c @@ -173,7 +173,7 @@ PROCESS_THREAD(shell_tcpsend_process, ev, data) } else if(ev == resolv_event_found) { /* Either found a hostname, or not. */ if((char *)data != NULL && - resolv_lookup((char *)data) != NULL) { + resolv_lookup((char *)data, &ipaddr) == RESOLV_STATUS_CACHED) { uip_ipaddr_copy(serveraddr, ipaddr); telnet_connect(&s, server, serveraddr, nick); } else { diff --git a/apps/shell/shell-udpsend.c b/apps/shell/shell-udpsend.c index 3568aa86e..ee20e2754 100644 --- a/apps/shell/shell-udpsend.c +++ b/apps/shell/shell-udpsend.c @@ -123,7 +123,7 @@ PROCESS_THREAD(shell_udpsend_process, ev, data) } else if(ev == resolv_event_found) { /* Either found a hostname, or not. */ if((char *)data != NULL && - resolv_lookup((char *)data) != NULL) { + resolv_lookup((char *)data, &ipaddr) == RESOLV_STATUS_CACHED) { uip_ipaddr_copy(serveraddr, ipaddr); telnet_connect(&s, server, serveraddr, nick); } else { diff --git a/apps/shell/shell-wget.c b/apps/shell/shell-wget.c index c2986d1a0..6374032fc 100644 --- a/apps/shell/shell-wget.c +++ b/apps/shell/shell-wget.c @@ -130,12 +130,14 @@ open_url(char *url) /* Try to lookup the hostname. If it fails, we initiate a hostname lookup and print out an informative message on the statusbar. */ if(uiplib_ipaddrconv(host, &addr) == 0) { + uip_ipaddr_t *addrptr; shell_output_str(&wget_command, "Not an IP address", ""); - if(resolv_lookup(host) == NULL) { + if(resolv_lookup(host, &addrptr) == RESOLV_STATUS_UNCACHED) { shell_output_str(&wget_command, "Not resolved", ""); resolv_query(host); return; } + uip_ipaddr_copy(&addr, addrptr); } #else /* UIP_UDP */ uiplib_ipaddrconv(host, &addr); @@ -171,7 +173,7 @@ PROCESS_THREAD(shell_wget_process, ev, data) } else if(ev == resolv_event_found) { /* Either found a hostname, or not. */ if((char *)data != NULL && - resolv_lookup((char *)data) != NULL) { + resolv_lookup((char *)data, NULL) == RESOLV_STATUS_CACHED) { open_url(url); } else { shell_output_str(&wget_command, "Host not found.", ""); diff --git a/apps/telnet/simpletelnet.c b/apps/telnet/simpletelnet.c index bbc43d435..42fe50f45 100644 --- a/apps/telnet/simpletelnet.c +++ b/apps/telnet/simpletelnet.c @@ -163,8 +163,7 @@ connect(void) addrptr = &addr; #if UIP_UDP if(uiplib_ipaddrconv(telnethost, &addr) == 0) { - addrptr = resolv_lookup(telnethost); - if(addrptr == NULL) { + if(resolv_lookup(telnethost, &addrptr) == RESOLV_STATUS_UNCACHED) { resolv_query(telnethost); show("Resolving host..."); return; @@ -252,7 +251,7 @@ PROCESS_THREAD(simpletelnet_process, ev, data) #if UIP_UDP } else if(ev == resolv_event_found) { if(strcmp(data, telnethost) == 0) { - if(resolv_lookup(telnethost) != NULL) { + if(resolv_lookup(telnethost, NULL) == RESOLV_STATUS_CACHED) { connect(); } else { show("Host not found"); diff --git a/apps/vnc/vnc.c b/apps/vnc/vnc.c index 8a1f53ef5..b9bdb7e07 100644 --- a/apps/vnc/vnc.c +++ b/apps/vnc/vnc.c @@ -134,8 +134,7 @@ connect(void) addrptr = &addr; if(uiplib_ipaddrconv(host, &addr) == 0) { - addrptr = resolv_lookup(host); - if(addrptr == NULL) { + if(resolv_lookup(host, &addrptr) == RESOLV_STATUS_UNCACHED) { resolv_query(host); show("Resolving host..."); return; @@ -198,7 +197,7 @@ PROCESS_THREAD(vnc_process, ev, data) LOADER_UNLOAD(); } else if(ev == resolv_event_found) { if(strcmp(data, host) == 0) { - if(resolv_lookup(host) != NULL) { + if(resolv_lookup(host, NULL) == RESOLV_STATUS_CACHED) { connect(); } else { show("Host not found"); diff --git a/apps/webbrowser/webclient.c b/apps/webbrowser/webclient.c index f5e6ca508..08c6ed211 100644 --- a/apps/webbrowser/webclient.c +++ b/apps/webbrowser/webclient.c @@ -140,9 +140,7 @@ webclient_get(const char *host, uint16_t port, const char *file) ipaddr = &addr; if(uiplib_ipaddrconv(host, &addr) == 0) { #if UIP_UDP - ipaddr = resolv_lookup(host); - - if(ipaddr == NULL) { + if(resolv_lookup(host,&ipaddr) != RESOLV_STATUS_CACHED) { return 0; } #else /* UIP_UDP */ @@ -486,7 +484,7 @@ webclient_appcall(void *state) init_connection(); }*/ #if UIP_UDP - if(resolv_lookup(s.host) == NULL) { + if(resolv_lookup(s.host, NULL) != RESOLV_STATUS_CACHED) { resolv_query(s.host); } #endif /* UIP_UDP */ diff --git a/apps/webbrowser/www.c b/apps/webbrowser/www.c index 53d8becf7..8de3d7578 100644 --- a/apps/webbrowser/www.c +++ b/apps/webbrowser/www.c @@ -348,11 +348,13 @@ open_url(void) /* Try to lookup the hostname. If it fails, we initiate a hostname lookup and print out an informative message on the statusbar. */ if(uiplib_ipaddrconv(host, &addr) == 0) { - if(resolv_lookup(host) == NULL) { + uip_ipaddr_t *addrptr; + if(resolv_lookup(host, &addrptr) != RESOLV_STATUS_CACHED) { resolv_query(host); show_statustext("Resolving host..."); return; } + uip_ipaddr_copy(&addr, addrptr); } #else /* UIP_UDP */ uiplib_ipaddrconv(host, &addr); @@ -553,7 +555,8 @@ PROCESS_THREAD(www_process, ev, data) #if UIP_UDP } else if(ev == resolv_event_found) { /* Either found a hostname, or not. */ - if((char *)data != NULL && resolv_lookup((char *)data) != NULL) { + if((char *)data != NULL && + resolv_lookup((char *)data, NULL) == RESOLV_STATUS_CACHED) { open_url(); } else { show_statustext("Host not found"); diff --git a/core/net/resolv.c b/core/net/resolv.c index c75bcc94c..f4cc310b9 100644 --- a/core/net/resolv.c +++ b/core/net/resolv.c @@ -21,10 +21,12 @@ /** * \file - * DNS host name to IP address resolver. + * DNS host name to IP address resolver. * \author Adam Dunkels + * \author Robert Quattlebaum * - * This file implements a DNS host name to IP address resolver. + * This file implements a DNS host name to IP address resolver, + * as well as an MDNS responder and resolver. */ /* @@ -62,41 +64,120 @@ #include "net/tcpip.h" #include "net/resolv.h" +#include "net/uip-udp-packet.h" +#include "lib/random.h" + +#ifndef DEBUG +#define DEBUG defined(CONTIKI_TARGET_COOJA) +#endif + #if UIP_UDP #include +#include +#include +#include #ifndef NULL #define NULL (void *)0 #endif /* NULL */ -#if UIP_CONF_IPV6 +#if !defined(__SDCC) && defined(SDCC_REVISION) +#define __SDCC 1 +#endif -/* Currently this implementation only supports IPv4 DNS lookups. - Until support for IPv6 is added, dummy functions are used to - enable compilation with IPv6. -*/ +#if VERBOSE_DEBUG +#define DEBUG_PRINTF(...) printf(__VA_ARGS__) +#else +#define DEBUG_PRINTF(...) do { } while(0) +#endif -process_event_t resolv_event_found; +#if DEBUG || VERBOSE_DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) do { } while(0) +#endif -PROCESS(resolv_process, "DNS resolver"); - -void resolv_conf(const uip_ipaddr_t *dnsserver) { } -uip_ipaddr_t *resolv_getserver(void) { return NULL; } -uip_ipaddr_t *resolv_lookup(const char *name) { return NULL; } -void resolv_query(const char *name) { } - -PROCESS_THREAD(resolv_process, ev, data) +#ifdef __SDCC +static int +strncasecmp(const char *s1, const char *s2, size_t n) { - PROCESS_BEGIN(); - resolv_event_found = process_alloc_event(); - PROCESS_END(); + /* TODO: Add case support! */ + return strncmp(s1, s2, n); } +static int +strcasecmp(const char *s1, const char *s2) +{ + /* TODO: Add case support! */ + return strcmp(s1, s2); +} +#endif -#else /* UIP_CONF_IPV6 */ +#define UIP_UDP_BUF ((struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN]) -/** \internal The maximum number of retries when asking for a name. */ -#define MAX_RETRIES 8 +/* If RESOLV_CONF_SUPPORTS_MDNS is set, then queries + * for domain names in the local TLD will use mDNS as + * described by draft-cheshire-dnsext-multicastdns. + */ +#ifndef RESOLV_CONF_SUPPORTS_MDNS +#define RESOLV_CONF_SUPPORTS_MDNS (1) +#endif + +#ifndef RESOLV_CONF_MDNS_INCLUDE_GLOBAL_V6_ADDRS +#define RESOLV_CONF_MDNS_INCLUDE_GLOBAL_V6_ADDRS (0) +#endif + +/** The maximum number of retries when asking for a name. */ +#ifndef RESOLV_CONF_MAX_RETRIES +#define RESOLV_CONF_MAX_RETRIES (4) +#endif + +#ifndef RESOLV_CONF_MAX_MDNS_RETRIES +#define RESOLV_CONF_MAX_MDNS_RETRIES (3) +#endif + +#ifndef RESOLV_CONF_MAX_DOMAIN_NAME_SIZE +#define RESOLV_CONF_MAX_DOMAIN_NAME_SIZE (32) +#endif + +#if !defined(CONTIKI_TARGET_NAME) && defined(BOARD) +#define stringy2(x) #x +#define stringy(x) stringy2(x) +#define CONTIKI_TARGET_NAME stringy(BOARD) +#endif + +#ifndef CONTIKI_CONF_DEFAULT_HOSTNAME +#ifdef CONTIKI_TARGET_NAME +#define CONTIKI_CONF_DEFAULT_HOSTNAME "contiki-"CONTIKI_TARGET_NAME +#else +#define CONTIKI_CONF_DEFAULT_HOSTNAME "contiki" +#endif +#endif + +#define DNS_TYPE_A (1) +#define DNS_TYPE_CNAME (5) +#define DNS_TYPE_PTR (12) +#define DNS_TYPE_MX (15) +#define DNS_TYPE_TXT (16) +#define DNS_TYPE_AAAA (28) +#define DNS_TYPE_SRV (33) +#define DNS_TYPE_ANY (255) +#define DNS_TYPE_NSEC (47) + +#define DNS_CLASS_IN (1) +#define DNS_CLASS_ANY (255) + +#ifndef DNS_PORT +#define DNS_PORT (53) +#endif + +#ifndef MDNS_PORT +#define MDNS_PORT (5353) +#endif + +#ifndef MDNS_RESPONDER_PORT +#define MDNS_RESPONDER_PORT (5354) +#endif /** \internal The DNS message header. */ struct dns_hdr { @@ -119,30 +200,57 @@ struct dns_hdr { uint16_t numextrarr; }; +#define RESOLV_ENCODE_INDEX(i) (uip_htons(i+1)) +#define RESOLV_DECODE_INDEX(i) (unsigned char)(uip_ntohs(i-1)) + +/** These default values for the DNS server are Google's public DNS: + * + */ +#if UIP_CONF_IPV6 +static uip_ipaddr_t resolv_default_dns_server = { + .u8 = { + 0x20, 0x01, 0x48, 0x60, + 0x48, 0x60, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x88, 0x88, + } +}; +#else +static uip_ipaddr_t resolv_default_dns_server = {.u8 = {8, 8, 8, 8} }; +#endif + /** \internal The DNS answer message structure. */ struct dns_answer { /* DNS answer record starts with either a domain name or a pointer - to a name already present somewhere in the packet. */ + * to a name already present somewhere in the packet. */ uint16_t type; uint16_t class; uint16_t ttl[2]; uint16_t len; +#if UIP_CONF_IPV6 + uint8_t ipaddr[16]; +#else uint8_t ipaddr[4]; +#endif }; struct namemap { #define STATE_UNUSED 0 -#define STATE_NEW 1 -#define STATE_ASKING 2 -#define STATE_DONE 3 -#define STATE_ERROR 4 +#define STATE_ERROR 1 +#define STATE_NEW 2 +#define STATE_ASKING 3 +#define STATE_DONE 4 uint8_t state; uint8_t tmr; uint8_t retries; uint8_t seqno; + unsigned long expiration; uint8_t err; - char name[32]; +#if RESOLV_CONF_SUPPORTS_MDNS + uint8_t is_mdns:1, is_probe:1; +#endif uip_ipaddr_t ipaddr; + char name[RESOLV_CONF_MAX_DOMAIN_NAME_SIZE + 1]; }; #ifndef UIP_CONF_RESOLV_ENTRIES @@ -151,7 +259,6 @@ struct namemap { #define RESOLV_ENTRIES UIP_CONF_RESOLV_ENTRIES #endif /* UIP_CONF_RESOLV_ENTRIES */ - static struct namemap names[RESOLV_ENTRIES]; static uint8_t seqno; @@ -164,271 +271,982 @@ process_event_t resolv_event_found; PROCESS(resolv_process, "DNS resolver"); -static void resolv_found(char *name, uip_ipaddr_t *ipaddr); +static void resolv_found(char *name, uip_ipaddr_t * ipaddr); enum { - EVENT_NEW_SERVER=0 + EVENT_NEW_SERVER = 0 }; -/*-----------------------------------------------------------------------------------*/ +/*---------------------------------------------------------------------------*/ +#if RESOLV_CONF_SUPPORTS_MDNS +/** \internal The DNS question message structure. */ +struct dns_question { + uint16_t type; + uint16_t class; +}; +static char resolv_hostname[RESOLV_CONF_MAX_DOMAIN_NAME_SIZE + 1]; + +enum { + MDNS_STATE_WAIT_BEFORE_PROBE, + MDNS_STATE_PROBING, + MDNS_STATE_READY, +}; + +static uint8_t mdns_state; + +#if UIP_CONF_IPV6 +#include "net/uip-ds6.h" +static const uip_ipaddr_t resolv_mdns_addr = { + .u8 = { + 0xff, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfb, + } +}; +#else /* UIP_CONF_IPV6 */ +static const uip_ipaddr_t resolv_mdns_addr = { + .u8 = {224, 0, 0, 251} +}; +#endif /* !UIP_CONF_IPV6 */ +static bool mdns_needs_host_announce; + +PROCESS(mdns_probe_process, "mDNS probe"); +#endif /* RESOLV_CONF_SUPPORTS_MDNS */ + +/*---------------------------------------------------------------------------*/ /** \internal - * Walk through a compact encoded DNS name and return the end of it. + * \brief Decodes a DNS name from the DNS format into the given string. + * \return True upon success, False if the size of the name would be too large. * - * \return The end of the name. + * \note `dest` must point to a buffer with at least + * `RESOLV_CONF_MAX_DOMAIN_NAME_SIZE+1` bytes large. + */ +static bool +decode_name(const unsigned char *query, char *dest, + const unsigned char *packet) +{ + int len = RESOLV_CONF_MAX_DOMAIN_NAME_SIZE; + + unsigned char n = *query++; + + //DEBUG_PRINTF("resolver: decoding name: \""); + + while(len && n) { + if(n & 0xc0) { + const uint16_t offset = query[0] + ((n & ~0xC0) << 8); + + //DEBUG_PRINTF("",offset); + query = packet + offset; + n = *query++; + } + + if(!n) + break; + + for(; n; n--) { + //DEBUG_PRINTF("%c",*query); + + *dest++ = *query++; + + if(!--len) { + *dest = 0; + return false; + } + } + + n = *query++; + + if(n) { + //DEBUG_PRINTF("."); + *dest++ = '.'; + len--; + } + } + + //DEBUG_PRINTF("\"\n"); + *dest = 0; + return len != 0; +} + +/*---------------------------------------------------------------------------*/ +/** \internal + */ +static bool +dns_name_isequal(const unsigned char *queryptr, const char *name, + const unsigned char *packet) +{ + unsigned char n = *queryptr++; + + if(*name == 0) + return false; + + while(n) { + if(n & 0xc0) { + queryptr = packet + queryptr[0] + ((n & ~0xC0) << 8); + n = *queryptr++; + } + + for(; n; n--) { + if(!*name) { + return false; + } + + if(tolower(*name++) != tolower(*queryptr++)) { + return false; + } + } + + n = *queryptr++; + + if((n != 0) && (*name++ != '.')) { + return false; + } + } + + if(*name == '.') + name++; + + return name[0] == 0; +} + +/*---------------------------------------------------------------------------*/ +/** \internal */ -/*-----------------------------------------------------------------------------------*/ static unsigned char * -parse_name(unsigned char *query) +skip_name(unsigned char *query) { unsigned char n; + DEBUG_PRINTF("resolver: skip name: "); + do { - n = *query++; - + n = *query; + if(n & 0xc0) { + DEBUG_PRINTF("", query[0] + ((n & ~0xC0) << 8)); + query++; + break; + } + + query++; + while(n > 0) { - /* printf("%c", *query);*/ + DEBUG_PRINTF("%c", *query); ++query; --n; }; - /* printf(".");*/ + DEBUG_PRINTF("."); } while(*query != 0); - /* printf("\n");*/ + DEBUG_PRINTF("\n"); return query + 1; } -/*-----------------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +/** \internal + */ +static unsigned char * +encode_name(unsigned char *query, const char *nameptr) +{ + char *nptr; + + --nameptr; + /* Convert hostname into suitable query format. */ + do { + uint8_t n = 0; + + ++nameptr; + nptr = (char *)query; + ++query; + for(n = 0; *nameptr != '.' && *nameptr != 0; ++nameptr) { + *query = *nameptr; + ++query; + ++n; + } + *nptr = n; + } while(*nameptr != 0); + + /* End the the name. */ + *query++ = 0; + + return query; +} + +#if RESOLV_CONF_SUPPORTS_MDNS + +/*---------------------------------------------------------------------------*/ +/** \internal + */ +static void +mdns_announce_requested(void) +{ + mdns_needs_host_announce = true; +} + +/*---------------------------------------------------------------------------*/ +/** \internal + */ +static void +start_name_collision_check(clock_time_t after) +{ + process_exit(&mdns_probe_process); + process_start(&mdns_probe_process, (void *)&after); +} + +/*---------------------------------------------------------------------------*/ +/** \internal + */ +static unsigned char * +mdns_write_announce_records(unsigned char *queryptr, uint8_t * count) +{ + struct dns_answer *ans; + +#if UIP_CONF_IPV6 + uint8_t i; + + for(i = 0; i < UIP_DS6_ADDR_NB; i++) { + if(uip_ds6_if.addr_list[i].isused +#if !RESOLV_CONF_MDNS_INCLUDE_GLOBAL_V6_ADDRS + && uip_is_addr_link_local(&uip_ds6_if.addr_list[i].ipaddr) +#endif + ) { + if(!*count) { + queryptr = encode_name(queryptr, resolv_hostname); + } else { + *queryptr++ = 0xc0; + *queryptr++ = sizeof(struct dns_hdr); + } + ans = (struct dns_answer *)queryptr; + + *queryptr++ = (uint8_t) ((DNS_TYPE_AAAA) >> 8); + *queryptr++ = (uint8_t) ((DNS_TYPE_AAAA)); + + *queryptr++ = (uint8_t) ((DNS_CLASS_IN | 0x8000) >> 8); + *queryptr++ = (uint8_t) ((DNS_CLASS_IN | 0x8000)); + + *queryptr++ = 0; + *queryptr++ = 0; + *queryptr++ = 0; + *queryptr++ = 120; + + *queryptr++ = 0; + *queryptr++ = sizeof(uip_ipaddr_t); + + uip_ipaddr_copy((uip_ipaddr_t *) queryptr, + &uip_ds6_if.addr_list[i].ipaddr); + queryptr += sizeof(uip_ipaddr_t); + (*count)++; + } + } +#else + queryptr = encode_name(queryptr, resolv_hostname); + ans = (struct dns_answer *)queryptr; + ans->type = UIP_HTONS(DNS_TYPE_A); + ans->class = UIP_HTONS(DNS_CLASS_IN | 0x8000); + ans->ttl[0] = 0; + ans->ttl[1] = UIP_HTONS(120); + ans->len = UIP_HTONS(sizeof(uip_ipaddr_t)); + uip_gethostaddr((uip_ipaddr_t *) ans->ipaddr); + queryptr = (unsigned char *)ans + sizeof(*ans); + (*count)++; +#endif + return queryptr; +} + +/*---------------------------------------------------------------------------*/ +/** \internal + * Called when we need to announce ourselves + */ +static size_t +mdns_prep_host_announce_packet(void) +{ + unsigned char *queryptr; + + struct dns_answer *ans; + + struct dns_hdr *hdr; + + uint8_t total_answers = 0; + + hdr = (struct dns_hdr *)uip_appdata; + + hdr->flags1 |= DNS_FLAG1_RESPONSE | DNS_FLAG1_AUTHORATIVE; + hdr->numquestions = UIP_HTONS(0); + hdr->numauthrr = 0; + hdr->numextrarr = 0; + + queryptr = (unsigned char *)hdr + sizeof(*hdr); + + queryptr = mdns_write_announce_records(queryptr, &total_answers); + + /* We now need to add an NSEC record to indicate + * that this is all there is. + */ + if(!total_answers) { + queryptr = encode_name(queryptr, resolv_hostname); + } else { + *queryptr++ = 0xc0; + *queryptr++ = sizeof(*hdr); + } + ans = (struct dns_answer *)queryptr; + ans->type = UIP_HTONS(DNS_TYPE_NSEC); + ans->class = UIP_HTONS(DNS_CLASS_IN | 0x8000); + ans->ttl[0] = 0; + ans->ttl[1] = UIP_HTONS(120); + ans->len = UIP_HTONS(8); + queryptr += 10; + *queryptr++ = 0xc0; + *queryptr++ = sizeof(*hdr); + *queryptr++ = 0x00; + *queryptr++ = 0x04; +#if UIP_CONF_IPV6 + *queryptr++ = 0x00; + *queryptr++ = 0x00; + *queryptr++ = 0x00; + *queryptr++ = 0x08; +#else + *queryptr++ = 0x40; + *queryptr++ = 0x00; + *queryptr++ = 0x00; + *queryptr++ = 0x00; +#endif + + hdr->numanswers = uip_htons(total_answers); + hdr->numextrarr = UIP_HTONS(1); + + return (queryptr - (unsigned char *)uip_appdata); +} +#endif // #if RESOLV_CONF_SUPPORTS_MDNS + +/*---------------------------------------------------------------------------*/ /** \internal * Runs through the list of names to see if there are any that have * not yet been queried and, if so, sends out a query. */ -/*-----------------------------------------------------------------------------------*/ static void check_entries(void) { + volatile uint8_t i; + + uint8_t *query; + register struct dns_hdr *hdr; - char *query, *nptr, *nameptr; - uint8_t i; - uint8_t n; + register struct namemap *namemapptr; - + for(i = 0; i < RESOLV_ENTRIES; ++i) { namemapptr = &names[i]; - if(namemapptr->state == STATE_NEW || - namemapptr->state == STATE_ASKING) { - etimer_set(&retry, CLOCK_SECOND); + if(namemapptr->state == STATE_NEW || namemapptr->state == STATE_ASKING) { + etimer_set(&retry, CLOCK_SECOND / 4); if(namemapptr->state == STATE_ASKING) { - if(--namemapptr->tmr == 0) { - if(++namemapptr->retries == MAX_RETRIES) { - namemapptr->state = STATE_ERROR; - resolv_found(namemapptr->name, NULL); - continue; - } - namemapptr->tmr = namemapptr->retries; - } else { - /* printf("Timer %d\n", namemapptr->tmr);*/ - /* Its timer has not run out, so we move on to next - entry. */ - continue; - } + if(--namemapptr->tmr == 0) { +#if RESOLV_CONF_SUPPORTS_MDNS + if(++namemapptr->retries == + (namemapptr->is_mdns ? RESOLV_CONF_MAX_MDNS_RETRIES : + RESOLV_CONF_MAX_RETRIES)) +#else + if(++namemapptr->retries == RESOLV_CONF_MAX_RETRIES) +#endif + { + /* STATE_ERROR basically means "not found". */ + namemapptr->state = STATE_ERROR; + + /* Keep the "not found" error valid for 30 seconds */ + namemapptr->expiration = clock_seconds() + 30; + + resolv_found(namemapptr->name, NULL); + continue; + } + namemapptr->tmr = namemapptr->retries * namemapptr->retries * 3; + +#if RESOLV_CONF_SUPPORTS_MDNS + if(namemapptr->is_probe) { + /* Probing retries are much more aggressive, 250ms */ + namemapptr->tmr = 2; + } +#endif + } else { + /* Its timer has not run out, so we move on to next + * entry. + */ + continue; + } } else { - namemapptr->state = STATE_ASKING; - namemapptr->tmr = 1; - namemapptr->retries = 0; + namemapptr->state = STATE_ASKING; + namemapptr->tmr = 1; + namemapptr->retries = 0; } hdr = (struct dns_hdr *)uip_appdata; memset(hdr, 0, sizeof(struct dns_hdr)); - hdr->id = uip_htons(i); - hdr->flags1 = DNS_FLAG1_RD; - hdr->numquestions = UIP_HTONS(1); - query = (char *)uip_appdata + 12; - nameptr = namemapptr->name; - --nameptr; - /* Convert hostname into suitable query format. */ - do { - ++nameptr; - nptr = query; - ++query; - for(n = 0; *nameptr != '.' && *nameptr != 0; ++nameptr) { - *query = *nameptr; - ++query; - ++n; - } - *nptr = n; - } while(*nameptr != 0); - { - static unsigned char endquery[] = - {0,0,1,0,1}; - memcpy(query, endquery, 5); + hdr->id = RESOLV_ENCODE_INDEX(i); +#if RESOLV_CONF_SUPPORTS_MDNS + if(!namemapptr->is_mdns || namemapptr->is_probe) { + hdr->flags1 = DNS_FLAG1_RD; } - uip_udp_send((unsigned char)(query + 5 - (char *)uip_appdata)); + if(namemapptr->is_mdns) { + hdr->id = 0; + } +#else + hdr->flags1 = DNS_FLAG1_RD; +#endif + hdr->numquestions = UIP_HTONS(1); + query = uip_appdata + sizeof(*hdr); + query = encode_name(query, namemapptr->name); +#if RESOLV_CONF_SUPPORTS_MDNS + if(namemapptr->is_probe) { + *query++ = (uint8_t) ((DNS_TYPE_ANY) >> 8); + *query++ = (uint8_t) ((DNS_TYPE_ANY)); + } else +#endif + { +#if UIP_CONF_IPV6 + *query++ = (uint8_t) ((DNS_TYPE_AAAA) >> 8); + *query++ = (uint8_t) ((DNS_TYPE_AAAA)); +#else + *query++ = (uint8_t) ((DNS_TYPE_A) >> 8); + *query++ = (uint8_t) ((DNS_TYPE_A)); +#endif + } + *query++ = (uint8_t) ((DNS_CLASS_IN) >> 8); + *query++ = (uint8_t) ((DNS_CLASS_IN)); +#if RESOLV_CONF_SUPPORTS_MDNS + if(namemapptr->is_mdns) { +#if RESOLV_CONF_SUPPORTS_MDNS + if(namemapptr->is_probe) { + /* This is our conflict detection request. + * In order to be in compliance with the MDNS + * spec, we need to add the records we are proposing + * to the rrauth section. + */ + uint8_t count = 0; + + query = mdns_write_announce_records(query, &count); + hdr->numauthrr = UIP_HTONS(count); + } +#endif + uip_udp_packet_sendto(resolv_conn, + uip_appdata, + (query - (uint8_t *) uip_appdata), + &resolv_mdns_addr, UIP_HTONS(MDNS_PORT) + ); + + PRINTF("resolver: (i=%d) Sent MDNS request for \"%s\".\n", i, + namemapptr->name); + } else { + uip_udp_packet_sendto(resolv_conn, + uip_appdata, + (query - (uint8_t *) uip_appdata), + &resolv_default_dns_server, UIP_HTONS(DNS_PORT) + ); + + PRINTF("resolver: (i=%d) Sent DNS request for \"%s\".\n", i, + namemapptr->name); + } +#else + uip_udp_packet_sendto(resolv_conn, + uip_appdata, + (query - (uint8_t *) uip_appdata), + &resolv_default_dns_server, UIP_HTONS(DNS_PORT) + ); + PRINTF("resolver: (i=%d) Sent DNS request for \"%s\".\n", i, + namemapptr->name); +#endif break; } } } -/*-----------------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ /** \internal * Called when new UDP data arrives. */ -/*-----------------------------------------------------------------------------------*/ static void newdata(void) { - unsigned char *nameptr; struct dns_answer *ans; - struct dns_hdr *hdr; - static uint8_t nquestions, nanswers; - static uint8_t i; + + struct dns_hdr const *hdr = (struct dns_hdr *)uip_appdata; + + unsigned char *queryptr = (unsigned char *)hdr + sizeof(*hdr); + register struct namemap *namemapptr; - - hdr = (struct dns_hdr *)uip_appdata; - /* printf("ID %d\n", uip_htons(hdr->id)); - printf("Query %d\n", hdr->flags1 & DNS_FLAG1_RESPONSE); - printf("Error %d\n", hdr->flags2 & DNS_FLAG2_ERR_MASK); - printf("Num questions %d, answers %d, authrr %d, extrarr %d\n", - uip_htons(hdr->numquestions), - uip_htons(hdr->numanswers), - uip_htons(hdr->numauthrr), - uip_htons(hdr->numextrarr)); - */ - /* The ID in the DNS header should be our entry into the name - table. */ - i = (uint8_t)uip_htons(hdr->id); - namemapptr = &names[i]; - if(i < RESOLV_ENTRIES && - namemapptr->state == STATE_ASKING) { + static uint8_t nquestions, nanswers, nauthrr = 0; - /* This entry is now finished. */ - namemapptr->state = STATE_DONE; + static int8_t i; + + /* We only care about the question(s) and the answers. The authrr + * and the extrarr are simply discarded. + */ + nquestions = (uint8_t) uip_ntohs(hdr->numquestions); + nanswers = (uint8_t) uip_ntohs(hdr->numanswers); + + DEBUG_PRINTF + ("resolver: flags1=0x%02X flags2=0x%02X nquestions=%d, nanswers=%d, nauthrr=%d, nextrarr=%d\n", + hdr->flags1, hdr->flags2, (uint8_t) nquestions, (uint8_t) nanswers, + (uint8_t) uip_ntohs(hdr->numauthrr), + (uint8_t) uip_ntohs(hdr->numextrarr)); + +/** QUESTION HANDLING SECTION ************************************************/ + + if(((hdr->flags1 & ~1) == 0) && (hdr->flags2 == 0)) { + /* This is an DNS request! */ +#if RESOLV_CONF_SUPPORTS_MDNS + + /* Skip requests with no questions. */ + if(!nquestions) { + return; + } + + queryptr = (unsigned char *)hdr + sizeof(*hdr); + + i = 0; + + for(; nquestions > 0; + queryptr = skip_name(queryptr) + sizeof(struct dns_question), + nquestions--) { + struct dns_question *question = + (struct dns_question *)skip_name(queryptr); + +#if __ARM__ + static struct dns_question aligned; + + memcpy(&aligned, question, sizeof(aligned)); + question = &aligned; +#endif + + DEBUG_PRINTF("resolver: Question %d: type=%d class=%d\n", ++i, + uip_htons(question->type), uip_htons(question->class)); + + if(((uip_ntohs(question->class) & 0x7FFF) != DNS_CLASS_IN) + || ((question->type != UIP_HTONS(DNS_TYPE_ANY)) + && (question->type != UIP_HTONS(DNS_TYPE_AAAA)) + && (question->type != UIP_HTONS(DNS_TYPE_A)) + )) { + /* Skip unrecognised records. */ + continue; + } + + if(!dns_name_isequal(queryptr, resolv_hostname, uip_appdata)) { + continue; + } + + PRINTF("resolver: THIS IS A REQUEST FOR US!!!\n"); + + if(mdns_state == MDNS_STATE_READY) { + /* We only send immediately if this isn't an MDNS request. + * Otherwise, we schedule ourselves to send later. + */ + if(UIP_UDP_BUF->srcport == UIP_HTONS(MDNS_PORT)) { + mdns_announce_requested(); + } else { + uip_udp_packet_sendto(resolv_conn, + uip_appdata, + mdns_prep_host_announce_packet(), + &UIP_UDP_BUF->srcipaddr, + UIP_UDP_BUF->srcport); + } + return; + } else { + PRINTF("resolver: But we are still probing. Waiting...\n"); + /* We are still probing. We need to do the mDNS + * probe race condition check here and make sure + * we don't need to delay probing for a second. + */ + nauthrr = (uint8_t) uip_ntohs(hdr->numauthrr); + + /* For now, we will always restart the collision check if + * there are *any* authority records present. + * In the future we should follow the spec more closely, + * but this should eventually converge to something reasonable. + */ + if(nauthrr) { + start_name_collision_check(CLOCK_SECOND * 1.5); + } + } + } +#endif + } + +/** ANSWER HANDLING SECTION **************************************************/ + + if(!nanswers) { + DEBUG_PRINTF("resolver: Skipping request/response with no answers.\n"); + /* We demand answers! */ + return; + } +#if RESOLV_CONF_SUPPORTS_MDNS + if(UIP_UDP_BUF->srcport == UIP_HTONS(MDNS_PORT) + && hdr->id == 0) { + /* OK, this was from MDNS. Things get a little weird here, + * because we can't use the `id` field. We will look up the + * appropriate request in a later step. */ + + i = -1; + namemapptr = NULL; + } else +#endif // RESOLV_CONF_SUPPORTS_MDNS + { + /* The ID in the DNS header should be our entry into the name table. */ + i = RESOLV_DECODE_INDEX(hdr->id); + + namemapptr = &names[i]; + + if(i >= RESOLV_ENTRIES || i < 0 || namemapptr->state != STATE_ASKING) { + PRINTF("resolver: Bad ID (%04X) on incoming DNS response\n", + uip_ntohs(hdr->id)); + return; + } + + PRINTF("resolver: Incoming response for \"%s\".\n", namemapptr->name); + + namemapptr->state = STATE_ERROR; /* We'll change this to DONE when we find the record. */ namemapptr->err = hdr->flags2 & DNS_FLAG2_ERR_MASK; + /* If we remain in the error state, keep it cached for 30 seconds. */ + namemapptr->expiration = clock_seconds() + 30; + /* Check for error. If so, call callback to inform. */ if(namemapptr->err != 0) { namemapptr->state = STATE_ERROR; resolv_found(namemapptr->name, NULL); return; } + } - /* We only care about the question(s) and the answers. The authrr - and the extrarr are simply discarded. */ - nquestions = (uint8_t)uip_htons(hdr->numquestions); - nanswers = (uint8_t)uip_htons(hdr->numanswers); - - /* Skip the name in the question. XXX: This should really be - checked agains the name in the question, to be sure that they - match. */ - nameptr = parse_name((uint8_t *)uip_appdata + 12) + 4; - - while(nanswers > 0) { - /* The first byte in the answer resource record determines if it - is a compressed record or a normal one. */ - if(*nameptr & 0xc0) { - /* Compressed name. */ - nameptr +=2; - /* printf("Compressed anwser\n");*/ - } else { - /* Not compressed name. */ - nameptr = parse_name((uint8_t *)nameptr); - } - - ans = (struct dns_answer *)nameptr; - /* printf("Answer: type %x, class %x, ttl %x, length %x\n", - uip_htons(ans->type), uip_htons(ans->class), (uip_htons(ans->ttl[0]) - << 16) | uip_htons(ans->ttl[1]), uip_htons(ans->len));*/ - - /* Check for IP address type and Internet class. Others are - discarded. */ - if(ans->type == UIP_HTONS(1) && - ans->class == UIP_HTONS(1) && - ans->len == UIP_HTONS(4)) { - /* printf("IP address %d.%d.%d.%d\n", - ans->ipaddr[0], - ans->ipaddr[1], - ans->ipaddr[2], - ans->ipaddr[3]);*/ - /* XXX: we should really check that this IP address is the one - we want. */ - for(i = 0; i < 4; i++) { - namemapptr->ipaddr.u8[i] = ans->ipaddr[i]; - } - - resolv_found(namemapptr->name, &namemapptr->ipaddr); - return; - } else { - nameptr = nameptr + 10 + uip_htons(ans->len); - } - --nanswers; + /* Discard all remaining questions */ + for(; nquestions > 0; queryptr += 4, nquestions--) { + if(namemapptr + && 0 != dns_name_isequal(queryptr, namemapptr->name, uip_appdata)) { + DEBUG_PRINTF("resolver: Question name doesn't look familiar...!\n"); + return; } + queryptr = skip_name(queryptr); + } + + /* Answer parsing loop */ + while(nanswers > 0) { + ans = (struct dns_answer *)skip_name(queryptr); + +#if __ARM__ + static struct dns_answer aligned; + + memcpy(&aligned, ans, sizeof(aligned)); + ans = &aligned; +#endif + +#if VERBOSE_DEBUG + static char debug_name[40]; + + decode_name(queryptr, debug_name, uip_appdata); + DEBUG_PRINTF("resolver: \"%s\", type %d, class %d, ttl %d, length %d\n", + debug_name, uip_ntohs(ans->type), + uip_ntohs(ans->class) & 0x7FFF, + (int)((uint32_t) uip_ntohs(ans->ttl[0]) << 16) | (uint32_t) + uip_ntohs(ans->ttl[1]), uip_ntohs(ans->len) + ); +#endif + + /* Check the class and length of the answer to make sure + * it matches what we are expecting + */ + if(((uip_ntohs(ans->class) & 0x7FFF) != DNS_CLASS_IN) + || (ans->len != UIP_HTONS(sizeof(uip_ipaddr_t))) + ) { + goto skip_to_next_answer; + } + +#if UIP_CONF_IPV6 + if(ans->type != UIP_HTONS(DNS_TYPE_AAAA)) { + goto skip_to_next_answer; + } +#else // UIP_CONF_IPV6 + if(ans->type != UIP_HTONS(DNS_TYPE_A)) { + goto skip_to_next_answer; + } +#endif + +#if RESOLV_CONF_SUPPORTS_MDNS + if(UIP_UDP_BUF->srcport == UIP_HTONS(MDNS_PORT) + && hdr->id == 0) { + int8_t available_i = RESOLV_ENTRIES; + + DEBUG_PRINTF("resolver: MDNS query.\n"); + + /* For MDNS, we need to actually look up the name we + * are looking for. + */ + for(i = 0; i < RESOLV_ENTRIES; ++i) { + namemapptr = &names[i]; + if(dns_name_isequal(queryptr, namemapptr->name, uip_appdata)) { + break; + } + if((namemapptr->state == STATE_UNUSED) + || (namemapptr->state == STATE_DONE + && clock_seconds() > namemapptr->expiration) + ) { + available_i = i; + } + } + if(i == RESOLV_ENTRIES) { + DEBUG_PRINTF("resolver: Unsolicited MDNS response.\n"); + i = available_i; + namemapptr = &names[i]; + if(!decode_name(queryptr, namemapptr->name, uip_appdata)) { + DEBUG_PRINTF("resolver: MDNS name too big to cache.\n"); + namemapptr = NULL; + goto skip_to_next_answer; + } + } + if(i == RESOLV_ENTRIES) { + DEBUG_PRINTF + ("resolver: Not enough room to keep track of unsolicited MDNS answer.\n"); + + if(dns_name_isequal(queryptr, resolv_hostname, uip_appdata)) { + /* Oh snap, they say they are us! We had better report them... */ + resolv_found(resolv_hostname, (uip_ipaddr_t *) ans->ipaddr); + } + namemapptr = NULL; + goto skip_to_next_answer; + } + namemapptr = &names[i]; + + } else +#endif // #if RESOLV_CONF_SUPPORTS_MDNS + { + /* This will force us to stop even if there are more answers. */ + nanswers = 1; + } + + if(namemapptr + && !dns_name_isequal(queryptr, namemapptr->name, uip_appdata)) { + DEBUG_PRINTF("resolver: Answer name doesn't match question...!\n"); + goto skip_to_next_answer; + } + + DEBUG_PRINTF("resolver: Answer for \"%s\" is usable.\n", + namemapptr->name); + + namemapptr->state = STATE_DONE; + namemapptr->expiration = ans->ttl[1] + (ans->ttl[0] << 8); + namemapptr->expiration += clock_seconds(); + + uip_ipaddr_copy(&namemapptr->ipaddr, (uip_ipaddr_t *) ans->ipaddr); + + resolv_found(namemapptr->name, &namemapptr->ipaddr); + + skip_to_next_answer: + queryptr = + (unsigned char *)skip_name(queryptr) + 10 + uip_htons(ans->len); + --nanswers; } } -/*-----------------------------------------------------------------------------------*/ + +#if RESOLV_CONF_SUPPORTS_MDNS +/*---------------------------------------------------------------------------*/ +/** + * \brief Changes the local hostname advertised by MDNS. + * \param hostname The new hostname to advertise. + */ +void +resolv_set_hostname(const char *hostname) +{ + strncpy(resolv_hostname, hostname, RESOLV_CONF_MAX_DOMAIN_NAME_SIZE); + + /* Add the .local suffix if it isn't already there */ + if(strlen(resolv_hostname) < 7 + || strcasecmp(resolv_hostname + strlen(resolv_hostname) - 6, + ".local") != 0) { + strncat(resolv_hostname, ".local", RESOLV_CONF_MAX_DOMAIN_NAME_SIZE); + } + + PRINTF("resolver: hostname changed to \"%s\"\n", resolv_hostname); + + start_name_collision_check(0); +} + +/*---------------------------------------------------------------------------*/ +/** + * \brief Returns the local hostname being advertised via MDNS. + * \return C-string containing the local hostname. + */ +const char * +resolv_get_hostname(void) +{ + return resolv_hostname; +} + +/*---------------------------------------------------------------------------*/ +/** \internal + * Process for probing for name conflicts. + */ +PROCESS_THREAD(mdns_probe_process, ev, data) +{ + static struct etimer delay; + + PROCESS_BEGIN(); + mdns_state = MDNS_STATE_WAIT_BEFORE_PROBE; + + PRINTF("mdns-probe: Process (re)started.\n"); + + /* Wait extra time if specified in data */ + if(NULL != data) { + PRINTF("mdns-probe: Probing will begin in %ld clocks.\n", + (long)*(clock_time_t *) data); + etimer_set(&delay, *(clock_time_t *) data); + PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_TIMER); + } + + /* We need to wait a random (0-250ms) period of time before + * probing to be in compliance with the MDNS spec. */ + etimer_set(&delay, CLOCK_SECOND * (random_rand() & 0xFF) / 1024); + PROCESS_WAIT_EVENT_UNTIL(ev == PROCESS_EVENT_TIMER); + + /* Begin searching for our name. */ + mdns_state = MDNS_STATE_PROBING; + resolv_query(resolv_hostname); + + do { + PROCESS_WAIT_EVENT_UNTIL(ev == resolv_event_found); + } while(strcasecmp(resolv_hostname, data) != 0); + + mdns_state = MDNS_STATE_READY; + mdns_announce_requested(); + + PRINTF("mdns-probe: Finished probing.\n"); + + PROCESS_END(); +} +#endif // RESOLV_CONF_SUPPORTS_MDNS + + +/*---------------------------------------------------------------------------*/ /** \internal * The main UDP function. */ -/*-----------------------------------------------------------------------------------*/ PROCESS_THREAD(resolv_process, ev, data) { - int i; - PROCESS_BEGIN(); - for(i = 0; i < RESOLV_ENTRIES; ++i) { - names[i].state = STATE_UNUSED; - } - resolv_conn = NULL; + memset(names, 0, sizeof(names)); + resolv_event_found = process_alloc_event(); - - + + PRINTF("resolver: Process started.\n"); + + resolv_conn = udp_new(NULL, 0, NULL); + resolv_conn->rport = 0; + +#if RESOLV_CONF_SUPPORTS_MDNS + PRINTF("resolver: Supports MDNS name resolution.\n"); +#endif + +#if RESOLV_CONF_SUPPORTS_MDNS + PRINTF("resolver: Supports MDNS responder.\n"); + uip_udp_bind(resolv_conn, UIP_HTONS(MDNS_PORT)); + +#if UIP_CONF_IPV6 + uip_ds6_maddr_add(&resolv_mdns_addr); +#endif + + resolv_set_hostname(CONTIKI_CONF_DEFAULT_HOSTNAME); +#endif /* RESOLV_CONF_SUPPORTS_MDNS */ + while(1) { PROCESS_WAIT_EVENT(); - - if(ev == PROCESS_EVENT_TIMER) { - if(resolv_conn != NULL) { - tcpip_poll_udp(resolv_conn); - } - } else if(ev == EVENT_NEW_SERVER) { - if(resolv_conn != NULL) { - uip_udp_remove(resolv_conn); - } - resolv_conn = udp_new((uip_ipaddr_t *)data, UIP_HTONS(53), NULL); - + if(ev == PROCESS_EVENT_TIMER) { + tcpip_poll_udp(resolv_conn); } else if(ev == tcpip_event) { - if(uip_udp_conn->rport == UIP_HTONS(53)) { - if(uip_poll()) { - check_entries(); - } - if(uip_newdata()) { - newdata(); - } + if(uip_udp_conn == resolv_conn) { + if(uip_newdata()) { + newdata(); + } + if(uip_poll()) { +#if RESOLV_CONF_SUPPORTS_MDNS + if(mdns_needs_host_announce) { + size_t len; + + PRINTF("resolver: Announcing that we are \"%s\".\n", + resolv_hostname); + + memset(uip_appdata, 0, sizeof(struct dns_hdr)); + + len = mdns_prep_host_announce_packet(); + + uip_udp_packet_sendto(resolv_conn, + uip_appdata, + len, &resolv_mdns_addr, UIP_HTONS(MDNS_PORT) + ); + + mdns_needs_host_announce = 0; + + /* Poll again in case this fired + * at the same time the event timer did. + */ + tcpip_poll_udp(resolv_conn); + } else +#endif + { + check_entries(); + } + } } } + +#if RESOLV_CONF_SUPPORTS_MDNS + if(mdns_needs_host_announce) { + tcpip_poll_udp(resolv_conn); + } +#endif } - + PROCESS_END(); } -/*-----------------------------------------------------------------------------------*/ + +/* For removing trailing dots in resolv_query() and resolve_lookup2(). */ +static char dns_name_without_dots[RESOLV_CONF_MAX_DOMAIN_NAME_SIZE + 1]; + +/*---------------------------------------------------------------------------*/ /** * Queues a name so that a question for the name will be sent out. * * \param name The hostname that is to be queried. */ -/*-----------------------------------------------------------------------------------*/ void resolv_query(const char *name) { static uint8_t i; + static uint8_t lseq, lseqi; - register struct namemap *nameptr; - + + register struct namemap *nameptr = 0; + lseq = lseqi = 0; - nameptr = 0; //compiler warning if not initialized - + + { /* Remove trailing dots, if present. */ + size_t len = strlen(name); + + if(name[len - 1] == '.') { + strncpy(dns_name_without_dots, name, sizeof(dns_name_without_dots)); + while(len && (dns_name_without_dots[len - 1] == '.')) { + dns_name_without_dots[--len] = 0; + } + name = dns_name_without_dots; + } + } + for(i = 0; i < RESOLV_ENTRIES; ++i) { nameptr = &names[i]; - if(nameptr->state == STATE_UNUSED) { + if(0 == strcasecmp(nameptr->name, name)) { break; } - if(seqno - nameptr->seqno > lseq) { + if((nameptr->state == STATE_UNUSED) + || (nameptr->state == STATE_DONE + && clock_seconds() > nameptr->expiration) + ) { + lseqi = i; + lseq = 255; + } else if(seqno - nameptr->seqno > lseq) { lseq = seqno - nameptr->seqno; lseqi = i; } @@ -439,16 +1257,41 @@ resolv_query(const char *name) nameptr = &names[i]; } + PRINTF("resolver: Starting query for \"%s\".\n", name); + + memset(nameptr, 0, sizeof(*nameptr)); + strncpy(nameptr->name, name, sizeof(nameptr->name)); nameptr->state = STATE_NEW; nameptr->seqno = seqno; ++seqno; - if(resolv_conn != NULL) { - tcpip_poll_udp(resolv_conn); +#if RESOLV_CONF_SUPPORTS_MDNS + { + size_t name_len = strlen(name); + + static const char local_suffix[] = "local"; + + if((name_len > (sizeof(local_suffix) - 1)) + && (0 == + strcasecmp(name + name_len - (sizeof(local_suffix) - 1), + local_suffix)) + ) { + PRINTF("resolver: Using MDNS to look up \"%s\".\n", name); + nameptr->is_mdns = 1; + } else { + nameptr->is_mdns = 0; + } } + nameptr->is_probe = (mdns_state == MDNS_STATE_PROBING) + && (0 == strcmp(nameptr->name, resolv_hostname)); +#endif + + /* Force check_entires() to run on our process. */ + process_post(&resolv_process, PROCESS_EVENT_TIMER, 0); } -/*-----------------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ /** * Look up a hostname in the array of known hostnames. * @@ -457,29 +1300,111 @@ resolv_query(const char *name) * was found. The function resolv_query() can be used to send a query * for a hostname. * - * \return A pointer to a 4-byte representation of the hostname's IP - * address, or NULL if the hostname was not found in the array of - * hostnames. */ -/*-----------------------------------------------------------------------------------*/ -uip_ipaddr_t * -resolv_lookup(const char *name) +resolv_status_t +resolv_lookup(const char *name, uip_ipaddr_t ** ipaddr) { + resolv_status_t ret = RESOLV_STATUS_UNCACHED; + static uint8_t i; + struct namemap *nameptr; - - /* Walk through the list to see if the name is in there. If it is - not, we return NULL. */ - for(i = 0; i < RESOLV_ENTRIES; ++i) { - nameptr = &names[i]; - if(nameptr->state == STATE_DONE && - strcmp(name, nameptr->name) == 0) { - return &nameptr->ipaddr; + + { /* Remove trailing dots, if present. */ + size_t len = strlen(name); + + if(name[len - 1] == '.') { + strncpy(dns_name_without_dots, name, sizeof(dns_name_without_dots) - 1); + name = dns_name_without_dots; + while(len && (dns_name_without_dots[len - 1] == '.')) { + dns_name_without_dots[--len] = 0; + } } } - return NULL; + +#if UIP_CONF_LOOPBACK_INTERFACE + if(strcmp(name, "localhost")) { +#if UIP_CONF_IPV6 + static uip_ipaddr_t loopback = { + .u8 = { + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + } + }; +#else + static uip_ipaddr_t loopback = { + .u8 = {127, 0, 0, 1} + }; +#endif + if(ipaddr) { + *ipaddr = &loopback; + } + ret = RESOLV_STATUS_CACHED; + } +#endif + + /* Walk through the list to see if the name is in there. */ + for(i = 0; i < RESOLV_ENTRIES; ++i) { + nameptr = &names[i]; + + if(strcasecmp(name, nameptr->name) == 0) { + switch (nameptr->state) { + case STATE_DONE: + if(clock_seconds() > nameptr->expiration) { + ret = RESOLV_STATUS_EXPIRED; + } else { + ret = RESOLV_STATUS_CACHED; + } + break; + case STATE_NEW: + case STATE_ASKING: + ret = RESOLV_STATUS_RESOLVING; + break; + case STATE_ERROR: /* Almost certainly a not-found error from server */ + if(clock_seconds() >= nameptr->expiration) { + ret = RESOLV_STATUS_NOT_FOUND; + } + break; + } + + if(ipaddr) { + *ipaddr = &nameptr->ipaddr; + } + + /* Break out of for loop. */ + break; + } + } + +#if VERBOSE_DEBUG + switch (ret) { + case RESOLV_STATUS_CACHED:{ + PRINTF("resolver: Found \"%s\" in cache.\n", name); + const uip_ipaddr_t *addr = *ipaddr; + + DEBUG_PRINTF + ("resolver: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x \n", + ((uint8_t *) addr)[0], ((uint8_t *) addr)[1], ((uint8_t *) addr)[2], + ((uint8_t *) addr)[3], ((uint8_t *) addr)[4], ((uint8_t *) addr)[5], + ((uint8_t *) addr)[6], ((uint8_t *) addr)[7], ((uint8_t *) addr)[8], + ((uint8_t *) addr)[9], ((uint8_t *) addr)[10], + ((uint8_t *) addr)[11], ((uint8_t *) addr)[12], + ((uint8_t *) addr)[13], ((uint8_t *) addr)[14], + ((uint8_t *) addr)[15]); + break; + } + default: + DEBUG_PRINTF("resolver: \"%s\" is NOT cached.\n", name); + break; + } +#endif + + return ret; } -/*-----------------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ /** * Obtain the currently configured DNS server. * @@ -487,49 +1412,104 @@ resolv_lookup(const char *name) * the currently configured DNS server or NULL if no DNS server has * been configured. */ -/*-----------------------------------------------------------------------------------*/ uip_ipaddr_t * resolv_getserver(void) { - if(resolv_conn == NULL) { - return NULL; - } - return &resolv_conn->ripaddr; + return &resolv_default_dns_server; } -/*-----------------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ /** * Configure a DNS server. * * \param dnsserver A pointer to a 4-byte representation of the IP * address of the DNS server to be configured. */ -/*-----------------------------------------------------------------------------------*/ void -resolv_conf(const uip_ipaddr_t *dnsserver) +resolv_conf(const uip_ipaddr_t * dnsserver) { - static uip_ipaddr_t server; - uip_ipaddr_copy(&server, dnsserver); - process_post(&resolv_process, EVENT_NEW_SERVER, &server); - - /* if(resolv_conn != NULL) { - uip_udp_remove(resolv_conn); - } - - resolv_conn = udp_new(dnsserver, 53, NULL);*/ + uip_ipaddr_copy(&resolv_default_dns_server, dnsserver); + process_post(&resolv_process, EVENT_NEW_SERVER, &resolv_default_dns_server); } -/*-----------------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ /** \internal * Callback function which is called when a hostname is found. * */ -/*-----------------------------------------------------------------------------------*/ static void -resolv_found(char *name, uip_ipaddr_t *ipaddr) +resolv_found(char *name, uip_ipaddr_t * ipaddr) { +#if RESOLV_CONF_SUPPORTS_MDNS + if(strncasecmp(resolv_hostname, name, strlen(resolv_hostname)) == 0 + && ipaddr +#if UIP_CONF_IPV6 + && !uip_ds6_is_my_addr(ipaddr) +#else + && uip_ipaddr_cmp(&uip_hostaddr, ipaddr) != 0 +#endif + ) { + uint8_t i; + + if(mdns_state == MDNS_STATE_PROBING) { + /* We found this new name while probing. + * We must now rename ourselves. + */ + PRINTF("resolver: Name collision detected for \"%s\".\n", name); + + /* Remove the ".local" suffix. */ + resolv_hostname[strlen(resolv_hostname) - 6] = 0; + + /* Append the last three hex parts of the link-level address. */ + for(i = 0; i < 3; i++) { + uint8_t val = uip_lladdr.addr[(UIP_LLADDR_LEN - 3) + i]; + + char append_str[4] = "-XX"; + + append_str[2] = (((val & 0xF) > 9) ? 'a' : '0') + (val & 0xF); + val >>= 4; + append_str[1] = (((val & 0xF) > 9) ? 'a' : '0') + (val & 0xF); + strncat(resolv_hostname, append_str, + sizeof(resolv_hostname) - strlen(resolv_hostname)); + } + + /* Re-add the .local suffix */ + strncat(resolv_hostname, ".local", RESOLV_CONF_MAX_DOMAIN_NAME_SIZE); + + start_name_collision_check(CLOCK_SECOND * 5); + } else if(mdns_state == MDNS_STATE_READY) { + /* We found a collision after we had already asserted + * that we owned this name. We need to immediately + * and explicitly begin probing. + */ + PRINTF("resolver: Possible name collision, probing...\n"); + start_name_collision_check(0); + } + + } else +#endif + +#if VERBOSE_DEBUG + if(ipaddr) { + PRINTF("resolver: Found address for \"%s\".\n", name); + PRINTF + ("resolver: %02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x \n", + ((uint8_t *) ipaddr)[0], ((uint8_t *) ipaddr)[1], + ((uint8_t *) ipaddr)[2], ((uint8_t *) ipaddr)[3], + ((uint8_t *) ipaddr)[4], ((uint8_t *) ipaddr)[5], + ((uint8_t *) ipaddr)[6], ((uint8_t *) ipaddr)[7], + ((uint8_t *) ipaddr)[8], ((uint8_t *) ipaddr)[9], + ((uint8_t *) ipaddr)[10], ((uint8_t *) ipaddr)[11], + ((uint8_t *) ipaddr)[12], ((uint8_t *) ipaddr)[13], + ((uint8_t *) ipaddr)[14], ((uint8_t *) ipaddr)[15]); + } else { + PRINTF("resolver: Unable to retrieve address for \"%s\".\n", name); + } +#endif + process_post(PROCESS_BROADCAST, resolv_event_found, name); } -/*-----------------------------------------------------------------------------------*/ -#endif /* UIP_CONF_IPV6 */ +/*---------------------------------------------------------------------------*/ #endif /* UIP_UDP */ /** @} */ diff --git a/core/net/resolv.h b/core/net/resolv.h index 85b666645..32a866bb9 100644 --- a/core/net/resolv.h +++ b/core/net/resolv.h @@ -40,6 +40,16 @@ #define __RESOLV_H__ #include "contiki.h" +#include "uip.h" + +/** If RESOLV_CONF_SUPPORTS_MDNS is set, then queries + * for domain names in the `local` TLD will use MDNS and + * will respond to MDNS queries for this device's hostname, + * as described by draft-cheshire-dnsext-multicastdns. + */ +#ifndef RESOLV_CONF_SUPPORTS_MDNS +#define RESOLV_CONF_SUPPORTS_MDNS (1) +#endif /** * Event that is broadcasted when a DNS name has been resolved. @@ -47,11 +57,53 @@ CCIF extern process_event_t resolv_event_found; /* Functions. */ -CCIF void resolv_conf(const uip_ipaddr_t *dnsserver); +CCIF void resolv_conf(const uip_ipaddr_t * dnsserver); + CCIF uip_ipaddr_t *resolv_getserver(void); -CCIF uip_ipaddr_t *resolv_lookup(const char *name); + +enum { + /** Hostname is fresh and usable. This response is cached and will eventually + * expire to RESOLV_STATUS_EXPIRED.*/ + RESOLV_STATUS_CACHED = 0, + + /** Hostname was not found in the cache. Use resolv_query() to look it up. */ + RESOLV_STATUS_UNCACHED, + + /** Hostname was found, but it's status has expired. The address returned + * should not be used. Use resolv_query() to freshen it up. + */ + RESOLV_STATUS_EXPIRED, + + /** The server has returned a not-found response for this domain name. + * This response is cached for the period described in the server. + * You may issue a new query at any time using resolv_query(), but + * you will generally want to wait until this domain's status becomes + * RESOLV_STATUS_EXPIRED. + */ + RESOLV_STATUS_NOT_FOUND, + + /** This hostname is in the process of being resolved. Try again soon. */ + RESOLV_STATUS_RESOLVING, + + /** Some sort of server error was encountered while trying to look up this + * record. This response is cached and will eventually expire to + * RESOLV_STATUS_EXPIRED. + */ + RESOLV_STATUS_ERROR, +}; + +typedef uint8_t resolv_status_t; + +CCIF resolv_status_t resolv_lookup(const char *name, uip_ipaddr_t ** ipaddr); + CCIF void resolv_query(const char *name); +#if RESOLV_CONF_SUPPORTS_MDNS +CCIF void resolv_set_hostname(const char *hostname); + +CCIF const char *resolv_get_hostname(void); +#endif + PROCESS_NAME(resolv_process); #endif /* __RESOLV_H__ */ diff --git a/core/net/uip-ds6.c b/core/net/uip-ds6.c index 16cc67606..81ca9d2c2 100644 --- a/core/net/uip-ds6.c +++ b/core/net/uip-ds6.c @@ -592,11 +592,11 @@ uip_ds6_get_global(int8_t state) /*---------------------------------------------------------------------------*/ uip_ds6_maddr_t * -uip_ds6_maddr_add(uip_ipaddr_t *ipaddr) +uip_ds6_maddr_add(const uip_ipaddr_t *ipaddr) { if(uip_ds6_list_loop ((uip_ds6_element_t *)uip_ds6_if.maddr_list, UIP_DS6_MADDR_NB, - sizeof(uip_ds6_maddr_t), ipaddr, 128, + sizeof(uip_ds6_maddr_t), (void*)ipaddr, 128, (uip_ds6_element_t **)&locmaddr) == FREESPACE) { locmaddr->isused = 1; uip_ipaddr_copy(&locmaddr->ipaddr, ipaddr); @@ -617,11 +617,11 @@ uip_ds6_maddr_rm(uip_ds6_maddr_t *maddr) /*---------------------------------------------------------------------------*/ uip_ds6_maddr_t * -uip_ds6_maddr_lookup(uip_ipaddr_t *ipaddr) +uip_ds6_maddr_lookup(const uip_ipaddr_t *ipaddr) { if(uip_ds6_list_loop ((uip_ds6_element_t *)uip_ds6_if.maddr_list, UIP_DS6_MADDR_NB, - sizeof(uip_ds6_maddr_t), ipaddr, 128, + sizeof(uip_ds6_maddr_t), (void*)ipaddr, 128, (uip_ds6_element_t **)&locmaddr) == FOUND) { return locmaddr; } diff --git a/core/net/uip-ds6.h b/core/net/uip-ds6.h index b697b45ac..cca15658d 100644 --- a/core/net/uip-ds6.h +++ b/core/net/uip-ds6.h @@ -315,9 +315,9 @@ uip_ds6_addr_t *uip_ds6_get_global(int8_t state); /** \name Multicast address list basic routines */ /** @{ */ -uip_ds6_maddr_t *uip_ds6_maddr_add(uip_ipaddr_t *ipaddr); +uip_ds6_maddr_t *uip_ds6_maddr_add(const uip_ipaddr_t *ipaddr); void uip_ds6_maddr_rm(uip_ds6_maddr_t *maddr); -uip_ds6_maddr_t *uip_ds6_maddr_lookup(uip_ipaddr_t *ipaddr); +uip_ds6_maddr_t *uip_ds6_maddr_lookup(const uip_ipaddr_t *ipaddr); /** @} */ diff --git a/core/net/uip.c b/core/net/uip.c index 24047e1d1..43e974df7 100644 --- a/core/net/uip.c +++ b/core/net/uip.c @@ -115,14 +115,14 @@ const uip_ipaddr_t uip_broadcast_addr = const uip_ipaddr_t uip_all_zeroes_addr = { { 0x0, /* rest is 0 */ } }; #if UIP_FIXEDETHADDR -const struct uip_eth_addr uip_ethaddr = {{UIP_ETHADDR0, +const uip_lladdr_t uip_lladdr = {{UIP_ETHADDR0, UIP_ETHADDR1, UIP_ETHADDR2, UIP_ETHADDR3, UIP_ETHADDR4, UIP_ETHADDR5}}; #else -struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}}; +uip_lladdr_t uip_lladdr = {{0,0,0,0,0,0}}; #endif /* The packet buffer that contains incoming packets. */ @@ -1050,7 +1050,7 @@ uip_process(uint8_t flag) uip_ipaddr_copy(&ICMPBUF->srcipaddr, &uip_hostaddr); ICMPBUF->options[0] = ICMP6_OPTION_TARGET_LINK_ADDRESS; ICMPBUF->options[1] = 1; /* Options length, 1 = 8 bytes. */ - memcpy(&(ICMPBUF->options[2]), &uip_ethaddr, sizeof(uip_ethaddr)); + memcpy(&(ICMPBUF->options[2]), &uip_lladdr, sizeof(uip_lladdr)); ICMPBUF->icmpchksum = 0; ICMPBUF->icmpchksum = ~uip_icmp6chksum(); diff --git a/core/net/uip_arp.c b/core/net/uip_arp.c index e1484901a..fdbc7bc20 100644 --- a/core/net/uip_arp.c +++ b/core/net/uip_arp.c @@ -311,8 +311,8 @@ uip_arp_arpin(void) BUF->opcode = UIP_HTONS(ARP_REPLY); memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6); - memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); - memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); + memcpy(BUF->shwaddr.addr, uip_lladdr.addr, 6); + memcpy(BUF->ethhdr.src.addr, uip_lladdr.addr, 6); memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6); uip_ipaddr_copy(&BUF->dipaddr, &BUF->sipaddr); @@ -408,8 +408,8 @@ uip_arp_out(void) memset(BUF->ethhdr.dest.addr, 0xff, 6); memset(BUF->dhwaddr.addr, 0x00, 6); - memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6); - memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6); + memcpy(BUF->ethhdr.src.addr, uip_lladdr.addr, 6); + memcpy(BUF->shwaddr.addr, uip_lladdr.addr, 6); uip_ipaddr_copy(&BUF->dipaddr, &ipaddr); uip_ipaddr_copy(&BUF->sipaddr, &uip_hostaddr); @@ -429,7 +429,7 @@ uip_arp_out(void) /* Build an ethernet header. */ memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6); } - memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6); + memcpy(IPBUF->ethhdr.src.addr, uip_lladdr.addr, 6); IPBUF->ethhdr.type = UIP_HTONS(UIP_ETHTYPE_IP); diff --git a/core/net/uip_arp.h b/core/net/uip_arp.h index a500fd4ce..1eb810448 100644 --- a/core/net/uip_arp.h +++ b/core/net/uip_arp.h @@ -54,7 +54,6 @@ #include "net/uip.h" -CCIF extern struct uip_eth_addr uip_ethaddr; /** * The Ethernet header. @@ -130,12 +129,12 @@ void uip_arp_timer(void); * * \hideinitializer */ -#define uip_setethaddr(eaddr) do {uip_ethaddr.addr[0] = eaddr.addr[0]; \ - uip_ethaddr.addr[1] = eaddr.addr[1];\ - uip_ethaddr.addr[2] = eaddr.addr[2];\ - uip_ethaddr.addr[3] = eaddr.addr[3];\ - uip_ethaddr.addr[4] = eaddr.addr[4];\ - uip_ethaddr.addr[5] = eaddr.addr[5];} while(0) +#define uip_setethaddr(eaddr) do {uip_lladdr.addr[0] = eaddr.addr[0]; \ + uip_lladdr.addr[1] = eaddr.addr[1];\ + uip_lladdr.addr[2] = eaddr.addr[2];\ + uip_lladdr.addr[3] = eaddr.addr[3];\ + uip_lladdr.addr[4] = eaddr.addr[4];\ + uip_lladdr.addr[5] = eaddr.addr[5];} while(0) /** @} */ diff --git a/cpu/6502/ipconfig/ipconfig.c b/cpu/6502/ipconfig/ipconfig.c index f0cf27754..dea8eb960 100644 --- a/cpu/6502/ipconfig/ipconfig.c +++ b/cpu/6502/ipconfig/ipconfig.c @@ -202,7 +202,7 @@ PROCESS_THREAD(ipconfig_process, ev, data) /* Allow resolver to set DNS server address. */ PROCESS_PAUSE(); - dhcpc_init(uip_ethaddr.addr, sizeof(uip_ethaddr.addr)); + dhcpc_init(uip_lladdr.addr, sizeof(uip_lladdr.addr)); while(1) { PROCESS_WAIT_EVENT(); diff --git a/cpu/arm/common/usb/cdc-eth/dhcps.c b/cpu/arm/common/usb/cdc-eth/dhcps.c index caaf78425..fdf0e8c34 100644 --- a/cpu/arm/common/usb/cdc-eth/dhcps.c +++ b/cpu/arm/common/usb/cdc-eth/dhcps.c @@ -298,7 +298,7 @@ create_msg(CC_REGISTER_ARG struct dhcp_msg *m) m->op = DHCP_REPLY; /* m->htype = DHCP_HTYPE_ETHERNET; */ /* m->hlen = DHCP_HLEN_ETHERNET; */ -/* memcpy(m->chaddr, &uip_ethaddr,DHCP_HLEN_ETHERNET); */ +/* memcpy(m->chaddr, &uip_lladdr,DHCP_HLEN_ETHERNET); */ m->hops = 0; m->secs = 0; memcpy(m->siaddr, &uip_hostaddr, 4); diff --git a/cpu/native/net/wpcap.c b/cpu/native/net/wpcap.c index ce44c7dc8..062cc476b 100644 --- a/cpu/native/net/wpcap.c +++ b/cpu/native/net/wpcap.c @@ -155,11 +155,11 @@ HMODULE wpcap; static struct pcap *pcap; -/* uip_ethaddr is defined in uip.c. It is not used in uip6.c. +/* uip_lladdr is defined in uip.c. It is not used in uip6.c. * If needed for some purpose it can be defined here */ #if UIP_CONF_IPV6 -//struct uip_eth_addr uip_ethaddr; +//struct uip_eth_addr uip_lladdr; #endif static int (* pcap_findalldevs)(struct pcap_if **, char *); @@ -266,7 +266,7 @@ set_ethaddr(struct in_addr addr) adapters->PhysicalAddress[4], adapters->PhysicalAddress[5]); log_message("set_ethaddr: ethernetaddr: ", buffer); #if UIP_CONF_IPV6 -// int i;for (i=0;i<6;i++) uip_ethaddr.addr[i] = adapters->PhysicalAddress[i]; +// int i;for (i=0;i<6;i++) uip_lladdr.addr[i] = adapters->PhysicalAddress[i]; #else uip_setethaddr((*(struct uip_eth_addr *)adapters->PhysicalAddress)); #endif @@ -328,7 +328,7 @@ set_ethaddr6(struct in_addr6 addr) adapters->PhysicalAddress[4], adapters->PhysicalAddress[5]); log_message("set_ethaddr: ethernetaddr: ", buffer); #if UIP_CONF_IPV6 -// int i;for (i=0;i<6;i++) uip_ethaddr.addr[i] = adapters->PhysicalAddress[i]; //does this need doing? +// int i;for (i=0;i<6;i++) uip_lladdr.addr[i] = adapters->PhysicalAddress[i]; //does this need doing? #else uip_setethaddr((*(struct uip_eth_addr *)adapters->PhysicalAddress)); #endif diff --git a/examples/ipv6/json-ws/json-ws-udp.c b/examples/ipv6/json-ws/json-ws-udp.c index d948e2bd8..f43a6f29a 100644 --- a/examples/ipv6/json-ws/json-ws-udp.c +++ b/examples/ipv6/json-ws/json-ws-udp.c @@ -75,9 +75,7 @@ json_ws_udp_setup(const char *host, uint16_t port) ipaddr = &server_ipaddr; if(uiplib_ipaddrconv(host, &server_ipaddr) == 0) { #if 0 && UIP_UDP - ipaddr = resolv_lookup(host); - - if(ipaddr == NULL) { + if(resolv_lookup(host, &ipaddr) != RESOLV_STATUS_CACHED) { return 0; } #else /* UIP_UDP */ diff --git a/examples/sky-shell-webserver/Makefile b/examples/sky-shell-webserver/Makefile index ba237314e..224409442 100644 --- a/examples/sky-shell-webserver/Makefile +++ b/examples/sky-shell-webserver/Makefile @@ -2,7 +2,7 @@ CONTIKI_PROJECT = sky-shell-webserver all: $(CONTIKI_PROJECT) PROJECT_SOURCEFILES = webserver-nogui.c HTTPD_CFS=1 -CFLAGS = -DWITH_UIP=1 +CFLAGS = -DWITH_UIP=1 -DRESOLV_CONF_SUPPORTS_MDNS=0 DEFINES=NETSTACK_MAC=nullmac_driver,NETSTACK_RDC=nullrdc_driver SMALL=1 diff --git a/examples/test-ipv6/tapdev6.c b/examples/test-ipv6/tapdev6.c index 0a5fab26d..77bf26ab7 100644 --- a/examples/test-ipv6/tapdev6.c +++ b/examples/test-ipv6/tapdev6.c @@ -187,7 +187,7 @@ tapdev_send(void) printf("\n"); } else { memcpy(&BUF->dest, addr, 6); - memcpy(&BUF->src, &uip_ethaddr, 6); + memcpy(&BUF->src, &uip_lladdr, 6); uip_len += sizeof(struct uip_eth_hdr); do_send(); } diff --git a/examples/udp-ipv6/udp-client.c b/examples/udp-ipv6/udp-client.c index 96c06e066..ce330970d 100644 --- a/examples/udp-ipv6/udp-client.c +++ b/examples/udp-ipv6/udp-client.c @@ -30,8 +30,10 @@ #include "contiki.h" #include "contiki-lib.h" #include "contiki-net.h" +#include "net/resolv.h" #include +#include #define DEBUG DEBUG_PRINT #include "net/uip-debug.h" @@ -42,7 +44,7 @@ static struct uip_udp_conn *client_conn; /*---------------------------------------------------------------------------*/ PROCESS(udp_client_process, "UDP client process"); -AUTOSTART_PROCESSES(&udp_client_process); +AUTOSTART_PROCESSES(&resolv_process,&udp_client_process); /*---------------------------------------------------------------------------*/ static void tcpip_handler(void) @@ -102,20 +104,43 @@ set_global_address(void) } #endif /* UIP_CONF_ROUTER */ /*---------------------------------------------------------------------------*/ -static void +static resolv_status_t set_connection_address(uip_ipaddr_t *ipaddr) { +#ifndef UDP_CONNECTION_ADDR +#if RESOLV_CONF_SUPPORTS_MDNS +#define UDP_CONNECTION_ADDR contiki-udp-server.local +#elif UIP_CONF_ROUTER +#define UDP_CONNECTION_ADDR aaaa:0:0:0:0212:7404:0004:0404 +#else +#define UDP_CONNECTION_ADDR fe80:0:0:0:6466:6666:6666:6666 +#endif +#endif /* !UDP_CONNECTION_ADDR */ + #define _QUOTEME(x) #x #define QUOTEME(x) _QUOTEME(x) -#ifdef UDP_CONNECTION_ADDR + + resolv_status_t status = RESOLV_STATUS_ERROR; + if(uiplib_ipaddrconv(QUOTEME(UDP_CONNECTION_ADDR), ipaddr) == 0) { - PRINTF("UDP client failed to parse address '%s'\n", QUOTEME(UDP_CONNECTION_ADDR)); + uip_ipaddr_t *resolved_addr = NULL; + status = resolv_lookup(QUOTEME(UDP_CONNECTION_ADDR),&resolved_addr); + if(status == RESOLV_STATUS_UNCACHED || status == RESOLV_STATUS_EXPIRED) { + PRINTF("Attempting to look up %s\n",QUOTEME(UDP_CONNECTION_ADDR)); + resolv_query(QUOTEME(UDP_CONNECTION_ADDR)); + status = RESOLV_STATUS_RESOLVING; + } else if(status == RESOLV_STATUS_CACHED && resolved_addr != NULL) { + PRINTF("Lookup of \"%s\" succeded!\n",QUOTEME(UDP_CONNECTION_ADDR)); + } else { + PRINTF("Lookup of \"%s\" failed. status = %d\n",QUOTEME(UDP_CONNECTION_ADDR),status); + } + if(resolved_addr) + uip_ipaddr_copy(ipaddr, resolved_addr); + } else { + status = RESOLV_STATUS_CACHED; } -#elif UIP_CONF_ROUTER - uip_ip6addr(ipaddr,0xaaaa,0,0,0,0x0212,0x7404,0x0004,0x0404); -#else - uip_ip6addr(ipaddr,0xfe80,0,0,0,0x6466,0x6666,0x6666,0x6666); -#endif /* UDP_CONNECTION_ADDR */ + + return status; } /*---------------------------------------------------------------------------*/ PROCESS_THREAD(udp_client_process, ev, data) @@ -132,7 +157,17 @@ PROCESS_THREAD(udp_client_process, ev, data) print_local_addresses(); - set_connection_address(&ipaddr); + static resolv_status_t status = RESOLV_STATUS_UNCACHED; + while(status != RESOLV_STATUS_CACHED) { + status = set_connection_address(&ipaddr); + + if(status == RESOLV_STATUS_RESOLVING) { + PROCESS_WAIT_EVENT_UNTIL(ev == resolv_event_found); + } else if(status != RESOLV_STATUS_CACHED) { + PRINTF("Can't get connection address.\n"); + PROCESS_YIELD(); + } + } /* new connection with remote host */ client_conn = udp_new(&ipaddr, UIP_HTONS(3000), NULL); diff --git a/examples/udp-ipv6/udp-server.c b/examples/udp-ipv6/udp-server.c index 1dc9279a5..8c88cf704 100644 --- a/examples/udp-ipv6/udp-server.c +++ b/examples/udp-ipv6/udp-server.c @@ -43,7 +43,7 @@ static struct uip_udp_conn *server_conn; PROCESS(udp_server_process, "UDP server process"); -AUTOSTART_PROCESSES(&udp_server_process); +AUTOSTART_PROCESSES(&resolv_process,&udp_server_process); /*---------------------------------------------------------------------------*/ static void tcpip_handler(void) @@ -94,6 +94,10 @@ PROCESS_THREAD(udp_server_process, ev, data) PROCESS_BEGIN(); PRINTF("UDP server started\n"); +#if RESOLV_CONF_SUPPORTS_MDNS + resolv_set_hostname("contiki-udp-server"); +#endif + #if UIP_CONF_ROUTER uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0); uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); diff --git a/examples/wget/wget.c b/examples/wget/wget.c index 5cac9b885..a792ad3ed 100644 --- a/examples/wget/wget.c +++ b/examples/wget/wget.c @@ -113,15 +113,16 @@ start_get(void) #if UIP_UDP /* First check if the host is an IP address. */ if(uiplib_ipaddrconv(host, &addr) == 0) { - + uip_ipaddr_t *addrptr; /* Try to lookup the hostname. If it fails, we initiate a hostname lookup and print out an informative message on the statusbar. */ - if(resolv_lookup(host) == NULL) { + if(resolv_lookup(host, &addrptr) != RESOLV_STATUS_CACHED) { resolv_query(host); puts("Resolving host..."); return; } + uip_ipaddr_copy(&addr, addrptr); } #else /* UIP_UDP */ uiplib_ipaddrconv(host, &addr); @@ -184,7 +185,7 @@ PROCESS_THREAD(wget_process, ev, data) } else if(ev == resolv_event_found) { /* Either found a hostname, or not. */ if((char *)data != NULL && - resolv_lookup((char *)data) != NULL) { + resolv_lookup((char *)data, NULL) == RESOLV_STATUS_CACHED) { start_get(); } else { puts("Host not found"); diff --git a/regression-tests/10-ipv6/01-cooja-ipv6-udp.csc b/regression-tests/10-ipv6/01-cooja-ipv6-udp.csc index c258e098e..8ba0cca25 100644 --- a/regression-tests/10-ipv6/01-cooja-ipv6-udp.csc +++ b/regression-tests/10-ipv6/01-cooja-ipv6-udp.csc @@ -49,7 +49,7 @@ make udp-server.cooja TARGET=cooja mtype512 Sender [CONTIKI_DIR]/examples/udp-ipv6/udp-client.c - make udp-client.cooja TARGET=cooja DEFINES=UDP_CONNECTION_ADDR=fe80::201:1:1:1 + make udp-client.cooja TARGET=cooja se.sics.cooja.interfaces.Position se.sics.cooja.interfaces.Battery se.sics.cooja.contikimote.interfaces.ContikiVib diff --git a/tools/cooja/apps/mspsim/example/helloworld.map b/tools/cooja/apps/mspsim/example/helloworld.map index f38a892cc..dc7b45074 100644 --- a/tools/cooja/apps/mspsim/example/helloworld.map +++ b/tools/cooja/apps/mspsim/example/helloworld.map @@ -685,7 +685,7 @@ LOAD /cygdrive/c/mspgcc/bin/../lib/gcc-lib/msp430/3.2.3/msp2/libgcc.a .data 0x000002d8 0x2 contiki-esb.a(service.o) .data 0x000002da 0x0 contiki-esb.a(timer.o) .data 0x000002da 0x6 contiki-esb.a(uip.o) - 0x000002da uip_ethaddr + 0x000002da uip_lladdr .data 0x000002e0 0xa contiki-esb.a(tr1001-drv.o) 0x000002e0 tr1001_drv_process .data 0x000002ea 0x0 contiki-esb.a(esb-sensors.o) diff --git a/tools/stm32w/wpcapslip6/wpcap6.c b/tools/stm32w/wpcapslip6/wpcap6.c index 3a41220d4..163a9cfbe 100644 --- a/tools/stm32w/wpcapslip6/wpcap6.c +++ b/tools/stm32w/wpcapslip6/wpcap6.c @@ -123,7 +123,7 @@ static int (* pcap_sendpacket)(struct pcap *, unsigned char *, int); #include "net/uip_arp.h" -struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}}; +struct uip_eth_addr uip_lladdr = {{0,0,0,0,0,0}}; static char interface_name[256] = ""; @@ -147,7 +147,7 @@ error_exit(char *msg1) static void setethaddr(struct uip_eth_addr *a) { - memcpy(&uip_ethaddr, a, sizeof(struct uip_eth_addr)); + memcpy(&uip_lladdr, a, sizeof(struct uip_eth_addr)); } /*---------------------------------------------------------------------------*/ static void @@ -271,7 +271,7 @@ wpcap_poll(char * buf) eth_hdr = (struct uip_eth_hdr *)packet; - if(memcmp(&uip_ethaddr,ð_hdr->src,sizeof(struct uip_eth_addr))!=0){ + if(memcmp(&uip_lladdr,ð_hdr->src,sizeof(struct uip_eth_addr))!=0){ // It's not a packet originated from the interface itself. return 0; } diff --git a/tools/wpcapslip/wpcap.c b/tools/wpcapslip/wpcap.c index b62ddbf25..ba641e4d7 100644 --- a/tools/wpcapslip/wpcap.c +++ b/tools/wpcapslip/wpcap.c @@ -150,7 +150,7 @@ struct arp_entry { struct uip_eth_addr ethaddr; uint8_t time; }; -static struct uip_eth_addr uip_ethaddr = {{0,0,0,0,0,0}}; +static struct uip_eth_addr uip_lladdr = {{0,0,0,0,0,0}}; static const uip_ipaddr_t all_zeroes_addr = { { 0x0, /* rest is 0 */ } }; static const struct uip_eth_addr broadcast_ethaddr = {{0xff,0xff,0xff,0xff,0xff,0xff}}; @@ -224,7 +224,7 @@ init_pcap(struct in_addr addr) static void setethaddr(struct uip_eth_addr *a) { - memcpy(&uip_ethaddr, a, sizeof(struct uip_eth_addr)); + memcpy(&uip_lladdr, a, sizeof(struct uip_eth_addr)); } /*---------------------------------------------------------------------------*/ static void @@ -439,8 +439,8 @@ arp_out(struct ethip_hdr *iphdr, int len) memset(arphdr->ethhdr.dest.addr, 0xff, 6); memset(arphdr->dhwaddr.addr, 0x00, 6); - memcpy(arphdr->ethhdr.src.addr, uip_ethaddr.addr, 6); - memcpy(arphdr->shwaddr.addr, uip_ethaddr.addr, 6); + memcpy(arphdr->ethhdr.src.addr, uip_lladdr.addr, 6); + memcpy(arphdr->shwaddr.addr, uip_lladdr.addr, 6); uip_ipaddr_copy(&arphdr->dipaddr, &ipaddr); uip_ipaddr_copy(&arphdr->sipaddr, &netaddr); @@ -460,7 +460,7 @@ arp_out(struct ethip_hdr *iphdr, int len) memcpy(iphdr->ethhdr.dest.addr, tabptr->ethaddr.addr, 6); } #endif /* 0 */ - memcpy(iphdr->ethhdr.src.addr, uip_ethaddr.addr, 6); + memcpy(iphdr->ethhdr.src.addr, uip_lladdr.addr, 6); iphdr->ethhdr.type = UIP_HTONS(UIP_ETHTYPE_IP); @@ -489,8 +489,8 @@ do_arp(void *buf, int len) hdr->opcode = UIP_HTONS(ARP_REPLY); memcpy(&hdr->dhwaddr.addr, &hdr->shwaddr.addr, 6); - memcpy(&hdr->shwaddr.addr, &uip_ethaddr.addr, 6); - memcpy(&hdr->ethhdr.src.addr, &uip_ethaddr.addr, 6); + memcpy(&hdr->shwaddr.addr, &uip_lladdr.addr, 6); + memcpy(&hdr->ethhdr.src.addr, &uip_lladdr.addr, 6); memcpy(&hdr->ethhdr.dest.addr, &hdr->dhwaddr.addr, 6); uip_ipaddr_copy(&tmpaddr, &hdr->dipaddr);