CDC/ECM driver for mbed, based on USBDevice by mbed-official. Uses PicoTCP to access Ethernet USB device. License: GPLv2

Dependents:   USBEthernet_TEST

Fork of USB_Ethernet by Daniele Lacamera

Revision:
2:540f6e142d59
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/pico_dns_client.c	Sat Aug 03 13:16:14 2013 +0000
@@ -0,0 +1,767 @@
+/*********************************************************************
+PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
+See LICENSE and COPYING for usage.
+
+.
+  
+Authors: Kristof Roelants
+*********************************************************************/
+#include "pico_config.h"
+#include "pico_stack.h"
+#include "pico_addressing.h"
+#include "pico_socket.h"
+#include "pico_ipv4.h"
+#include "pico_dns_client.h"
+#include "pico_tree.h"
+
+#ifdef PICO_SUPPORT_DNS_CLIENT
+
+#define dns_dbg(...) do{}while(0)
+//#define dns_dbg dbg
+
+/* DNS response length */
+#define PICO_DNS_MAX_RESPONSE_LEN 256
+
+/* DNS client retransmission time (msec) + frequency */
+#define PICO_DNS_CLIENT_RETRANS 4000
+#define PICO_DNS_CLIENT_MAX_RETRANS 3
+
+/* Default nameservers */
+#define PICO_DNS_NS_GOOGLE "8.8.8.8"
+
+/* Nameserver port */
+#define PICO_DNS_NS_PORT 53
+
+/* FLAG values */
+#define PICO_DNS_QR_QUERY 0
+#define PICO_DNS_QR_RESPONSE 1
+#define PICO_DNS_OPCODE_QUERY 0
+#define PICO_DNS_OPCODE_IQUERY 1
+#define PICO_DNS_OPCODE_STATUS 2
+#define PICO_DNS_AA_NO_AUTHORITY 0
+#define PICO_DNS_AA_IS_AUTHORITY 1
+#define PICO_DNS_TC_NO_TRUNCATION 0
+#define PICO_DNS_TC_IS_TRUNCATED 1
+#define PICO_DNS_RD_NO_DESIRE 0
+#define PICO_DNS_RD_IS_DESIRED 1
+#define PICO_DNS_RA_NO_SUPPORT 0
+#define PICO_DNS_RA_IS_SUPPORTED 1
+#define PICO_DNS_RCODE_NO_ERROR 0
+#define PICO_DNS_RCODE_EFORMAT 1
+#define PICO_DNS_RCODE_ESERVER 2
+#define PICO_DNS_RCODE_ENAME 3
+#define PICO_DNS_RCODE_ENOIMP 4
+#define PICO_DNS_RCODE_EREFUSED 5
+
+/* QTYPE values */
+#define PICO_DNS_TYPE_A 1
+#define PICO_DNS_TYPE_PTR 12
+
+/* QCLASS values */
+#define PICO_DNS_CLASS_IN 1
+
+/* Compression values */
+#define PICO_DNS_LABEL 0
+#define PICO_DNS_POINTER 3
+
+/* TTL values */
+#define PICO_DNS_MAX_TTL 604800 /* one week */
+
+/* Header flags */
+#define FLAG_QR(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 15)) | (x << 15)) 
+#define FLAG_OPCODE(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0xF << 11)) | (x << 11)) 
+#define FLAG_AA(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 10)) | (x << 10)) 
+#define FLAG_TC(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 9)) | (x << 9)) 
+#define FLAG_RD(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 8)) | (x << 8)) 
+#define FLAG_RA(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 7)) | (x << 7)) 
+#define FLAG_Z(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x7 << 4)) | (x << 4)) 
+#define FLAG_RCODE(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0xF)) | x) 
+
+#define GET_FLAG_QR(hdr) ((((hdr)->flags) & (1 << 15)) != 0) 
+#define GET_FLAG_OPCODE(hdr) ((((hdr)->flags) & (0xF << 11)) >> 11) 
+#define GET_FLAG_AA(hdr) ((((hdr)->flags) & (1 << 10)) != 0) 
+#define GET_FLAG_TC(hdr) ((((hdr)->flags) & (1 << 9)) != 0) 
+#define GET_FLAG_RD(hdr) ((((hdr)->flags) & (1 << 8)) != 0) 
+#define GET_FLAG_RA(hdr) ((((hdr)->flags) & (1 << 7)) != 0) 
+#define GET_FLAG_Z(hdr) ((((hdr)->flags) & (0x7 << 4)) >> 4) 
+#define GET_FLAG_RCODE(hdr) (((hdr)->flags) & (0x0F)) 
+
+/* RFC 1025 section 4. MESSAGES */
+struct __attribute__((packed)) dns_message_hdr
+{
+  uint16_t id;
+  uint16_t flags;
+  uint16_t qdcount;
+  uint16_t ancount;
+  uint16_t nscount;
+  uint16_t arcount;
+};
+
+struct __attribute__((packed)) dns_query_suffix
+{
+  /* NAME - domain name to which this resource record pertains */
+  uint16_t qtype;
+  uint16_t qclass;
+};
+
+struct __attribute__((packed)) dns_answer_suffix
+{
+  /* NAME - domain name to which this resource record pertains */
+  uint16_t qtype;
+  uint16_t qclass;
+  uint32_t ttl;
+  uint16_t rdlength;
+  /* RDATA - variable length string of octets that describes the resource */
+};
+
+struct pico_dns_ns
+{
+  struct pico_ip4 ns; /* Nameserver */
+};
+
+static int dns_ns_cmp(void *ka, void *kb)
+{
+    struct pico_dns_ns *a = ka, *b = kb;
+  if (a->ns.addr < b->ns.addr)
+    return -1; 
+  else if (a->ns.addr > b->ns.addr)
+    return 1;
+  else
+    return 0;
+} 
+    
+PICO_TREE_DECLARE(NSTable,dns_ns_cmp);
+
+int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag)
+{
+  struct pico_dns_ns test, *key = NULL;
+
+  if (!ns) {
+    pico_err = PICO_ERR_EINVAL;
+    return -1;
+  }
+
+  switch (flag)
+  {
+    case PICO_DNS_NS_ADD:
+      key = pico_zalloc(sizeof(struct pico_dns_ns));
+      if (!key) {
+        pico_err = PICO_ERR_ENOMEM;
+        return -1;
+      }
+      key->ns = *ns;
+
+      if(pico_tree_insert(&NSTable,key)){
+        dns_dbg("DNS WARNING: nameserver %08X already added\n",ns->addr);
+        pico_err = PICO_ERR_EINVAL;
+        pico_free(key);
+        return -1; /* Element key already exists */
+      }
+      dns_dbg("DNS: nameserver %08X added\n", ns->addr);
+      /* If default NS found, remove it */
+      pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &test.ns.addr);
+      if (ns->addr != test.ns.addr) {
+
+          key = pico_tree_findKey(&NSTable,&test);
+        if (key) {
+            if(pico_tree_delete(&NSTable,key)) {
+            dns_dbg("DNS: default nameserver %08X removed\n", test.ns.addr);
+            pico_free(key);
+          } else {
+            pico_err = PICO_ERR_EAGAIN;
+            return -1;
+          }
+        }
+      }
+      break;
+
+    case PICO_DNS_NS_DEL:
+      test.ns = *ns;
+
+      key = pico_tree_findKey(&NSTable,&test);
+      if (!key) {
+        dns_dbg("DNS WARNING: nameserver %08X not found\n", ns->addr);
+        pico_err = PICO_ERR_EINVAL;
+        return -1;
+      }
+      /* RB_REMOVE returns pointer to removed element, NULL to indicate error */
+
+            if(pico_tree_delete(&NSTable,key)) {
+        dns_dbg("DNS: nameserver %08X removed\n",key->ns.addr);
+        pico_free(key);
+      } else {
+        pico_err = PICO_ERR_EAGAIN;
+        return -1;
+      }
+      /* If no NS left, add default NS */
+      if(pico_tree_first(&NSTable) == NULL){
+        dns_dbg("DNS: add default nameserver\n");
+        return pico_dns_client_init();
+      }
+      break;
+
+    default:
+      pico_err = PICO_ERR_EINVAL;
+      return -1;
+  }
+  return 0;
+}
+
+int pico_dns_client_init()
+{
+  struct pico_ip4 default_ns;
+  if (pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &default_ns.addr) != 0) {
+    pico_err = PICO_ERR_EINVAL;
+    return -1;
+  }
+  return pico_dns_client_nameserver(&default_ns, PICO_DNS_NS_ADD);
+}
+
+struct pico_dns_key
+{
+  char *q_hdr;
+  uint16_t len;
+  uint16_t id;
+  uint16_t qtype;
+  uint16_t qclass;
+  uint8_t retrans;
+  struct pico_dns_ns q_ns;
+  struct pico_socket *s;
+  void (*callback)(char *, void *);
+  void *arg;
+};
+
+static int dns_cmp(void *ka, void *kb)
+{
+    struct pico_dns_key *a = ka,*b = kb;
+  if (a->id < b->id)
+    return -1; 
+  else if (a->id > b->id)
+    return 1;
+  else
+    return 0;
+} 
+    
+PICO_TREE_DECLARE(DNSTable,dns_cmp);
+
+static int pico_dns_client_strlen(const char *url)
+{
+  uint16_t len = 0;
+  int p;
+
+  if (!url)
+    return -1;
+
+  while ((p = *url++) != 0) {
+    len++;
+  }
+  return len;
+}
+
+/* Replace '.' by the label length */
+static int pico_dns_client_label(char *ptr)
+{
+  char *l;
+  uint8_t lbl_len = 0;
+  int p;
+
+  if (!ptr)
+    return -1;
+
+  l = ptr++;
+  while ((p = *ptr++) != 0){
+    if (p == '.') {
+      *l = lbl_len;
+      l = ptr - 1;
+      lbl_len = 0;
+    } else {
+      lbl_len++;
+    }
+  }
+  *l = lbl_len;
+  return 0;
+}
+
+/* Replace the label length by '.' */
+static int pico_dns_client_reverse_label(char *ptr)
+{
+  char *l;
+  int p;
+
+  if(!ptr)
+    return -1;
+
+  l = ptr;
+  while ((p = *ptr++) != 0){
+    ptr += p;
+    *l = '.';
+    l = ptr;
+  }
+  return 0;
+}
+
+/* Seek the end of a string */
+static char *pico_dns_client_seek(char *ptr)
+{
+  int p;
+
+  if (!ptr)
+    return NULL;
+
+  while ((p = *ptr++) != 0);
+
+  return ptr++;
+}
+
+static inline void pico_dns_client_construct_hdr(struct dns_message_hdr *hdr, uint16_t id)
+{
+  hdr->id = short_be(id);
+  FLAG_QR(hdr, PICO_DNS_QR_QUERY); 
+  FLAG_OPCODE(hdr, PICO_DNS_OPCODE_QUERY); 
+  FLAG_AA(hdr, PICO_DNS_AA_NO_AUTHORITY); 
+  FLAG_TC(hdr, PICO_DNS_TC_NO_TRUNCATION); 
+  FLAG_RD(hdr, PICO_DNS_RD_IS_DESIRED); 
+  FLAG_RA(hdr, PICO_DNS_RA_NO_SUPPORT); 
+  FLAG_Z(hdr, 0); 
+  FLAG_RCODE(hdr, PICO_DNS_RCODE_NO_ERROR); 
+  hdr->flags = short_be(hdr->flags);
+  hdr->qdcount = short_be(1);
+  hdr->ancount = short_be(0);
+  hdr->nscount = short_be(0);
+  hdr->arcount = short_be(0);
+}
+
+static inline void pico_dns_client_hdr_ntoh(struct dns_message_hdr *hdr)
+{
+  hdr->id = short_be(hdr->id);
+  hdr->flags = short_be(hdr->flags);
+  hdr->qdcount = short_be(hdr->qdcount);
+  hdr->ancount = short_be(hdr->ancount);
+  hdr->nscount = short_be(hdr->nscount);
+  hdr->arcount = short_be(hdr->arcount);
+}
+
+
+static int pico_dns_client_mirror(char *ptr)
+{
+  unsigned char buf[4] = {0};
+  char *m;
+  int cnt = 0;
+  int p, i;
+
+  if (!ptr)
+    return -1;
+
+  m = ptr;
+  while ((p = *ptr++) != 0)
+  {
+    if (pico_is_digit(p)) {
+      buf[cnt] = (10 * buf[cnt]) + (p - '0');
+    } else if (p == '.') {
+        cnt++;
+    } else {
+      return -1;
+    }
+  }
+
+  /* Handle short notation */
+  if(cnt == 1){
+    buf[3] = buf[1];
+    buf[1] = 0;
+    buf[2] = 0;
+  }else if (cnt == 2){
+    buf[3] = buf[2];
+    buf[2] = 0;
+  }else if(cnt != 3){
+    /* String could not be parsed, return error */
+    return -1;
+  }
+
+  ptr = m;
+  for(i = 3; i >= 0; i--)
+  {
+    if(buf[i] > 99){
+      *ptr++ = '0' + (buf[i] / 100);
+      *ptr++ = '0' + ((buf[i] % 100) / 10);
+      *ptr++ = '0' + ((buf[i] % 100) % 10);
+    }else if(buf[i] > 9){
+      *ptr++ = '0' + (buf[i] / 10);
+      *ptr++ = '0' + (buf[i] % 10);
+    }else{
+      *ptr++ = '0' + buf[i];
+    }
+    if(i > 0)
+      *ptr++ = '.';
+  }
+
+  return 0;
+}
+
+static struct pico_dns_key *pico_dns_client_idcheck(uint16_t id)
+{
+  struct pico_dns_key test;
+
+  test.id = id;
+  return pico_tree_findKey(&DNSTable,&test);
+}
+
+static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s);
+
+static int pico_dns_client_send(struct pico_dns_key *key)
+{
+  struct pico_socket *s;
+  int w = 0;
+
+  dns_dbg("DNS: sending query to %08X\n", key->q_ns.ns.addr);
+  s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback);
+  if (!s)
+    return -1; 
+  key->s = s;
+  if (pico_socket_connect(s, &key->q_ns.ns, short_be(PICO_DNS_NS_PORT)) != 0)
+    return -1;
+  w = pico_socket_send(s, key->q_hdr, key->len);
+  if (w <= 0)
+    return -1;
+
+  return 0;
+}
+
+static void pico_dns_client_retransmission(unsigned long now, void *arg)
+{
+  struct pico_dns_key *key = (struct pico_dns_key *)arg;
+  struct pico_dns_ns *q_ns = NULL;
+
+  if (!key->retrans) {
+    dns_dbg("DNS: no retransmission!\n");
+    pico_free(key->q_hdr);
+
+    if(pico_tree_delete(&DNSTable,key))
+      pico_free(key);
+  }
+  else if (key->retrans <= PICO_DNS_CLIENT_MAX_RETRANS) {
+    key->retrans++;
+    dns_dbg("DNS: retransmission! (%u attempts)\n", key->retrans);
+        // ugly hack
+    q_ns = pico_tree_next(pico_tree_findNode(&NSTable,&key->q_ns))->keyValue;
+    if (q_ns)
+      key->q_ns = *q_ns; 
+    else
+        key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
+    pico_dns_client_send(key);
+    pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key);
+  } else {
+    dns_dbg("DNS ERROR: no reply from nameservers! (%u attempts)\n", key->retrans);
+    pico_socket_close(key->s);
+    pico_err = PICO_ERR_EIO;
+    key->callback(NULL, key->arg);
+    pico_free(key->q_hdr);
+    /* RB_REMOVE returns pointer to removed element, NULL to indicate error */
+
+    if(pico_tree_delete(&DNSTable,key))
+      pico_free(key);
+  }
+}
+
+static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s)
+{
+  char *q_qname, *q_suf, *a_hdr, *a_qname, *a_suf, *a_rdata;
+  struct dns_message_hdr *hdr;
+  struct dns_query_suffix query_suf;
+  struct dns_answer_suffix answer_suf;
+  struct pico_dns_key test, *key;
+  char *answer;
+  char dns_answer[PICO_DNS_MAX_RESPONSE_LEN] = {0};
+  uint8_t valid_suffix = 0;
+  uint16_t compression = 0;
+  int i = 0, r = 0;
+
+  if (ev & PICO_SOCK_EV_RD) {
+    r = pico_socket_read(s, dns_answer, PICO_DNS_MAX_RESPONSE_LEN);
+    pico_socket_close(s);
+    if (r == PICO_DNS_MAX_RESPONSE_LEN || r < (int)sizeof(struct dns_message_hdr)) {
+      dns_dbg("DNS ERROR: received incorrect number(%d) of bytes\n", r);
+      return;
+    }
+
+    /* Check header validity */
+    a_hdr = dns_answer;
+    hdr = (struct dns_message_hdr *) a_hdr;
+    pico_dns_client_hdr_ntoh(hdr);
+    if (GET_FLAG_QR(hdr) != PICO_DNS_QR_RESPONSE || GET_FLAG_OPCODE(hdr) != PICO_DNS_OPCODE_QUERY 
+        || GET_FLAG_TC(hdr) == PICO_DNS_TC_IS_TRUNCATED || GET_FLAG_RCODE(hdr) != PICO_DNS_RCODE_NO_ERROR) {
+      dns_dbg("DNS ERROR: OPCODE %d | TC %d | RCODE %d\n", GET_FLAG_OPCODE(hdr), GET_FLAG_TC(hdr), GET_FLAG_RCODE(hdr));
+      return;
+    }
+
+    if (hdr->ancount < 1 || r < (int)(sizeof(struct dns_message_hdr) + hdr->qdcount * sizeof(struct dns_query_suffix)
+            + hdr->ancount * sizeof(struct dns_answer_suffix))) {
+      dns_dbg("DNS ERROR: ancount < 1 OR received number(%d) of bytes too low\n", r);
+      return;
+    }
+
+    /* Find DNS key */
+    test.id = hdr->id;
+
+    key = pico_tree_findKey(&DNSTable,&test);
+    if (!key) {
+      dns_dbg("DNS WARNING: key with id %u not found\n", hdr->id);
+      return;
+    }
+    key->retrans = 0;
+
+    /* Check query suffix validity */
+    q_qname = a_hdr + sizeof(struct dns_message_hdr);
+    q_suf = pico_dns_client_seek(q_qname);
+    query_suf = *(struct dns_query_suffix *) q_suf;
+    if (short_be(query_suf.qtype) != key->qtype || short_be(query_suf.qclass) != key->qclass) {
+      dns_dbg("DNS ERROR: received qtype (%u) or qclass (%u) incorrect\n", short_be(query_suf.qtype), short_be(query_suf.qclass));
+      return;
+    }
+
+    /* Seek answer suffix */
+    a_qname = q_suf + sizeof(struct dns_query_suffix);
+    a_suf = a_qname;
+    while(i++ < hdr->ancount) {
+      uint16_t comp_h = short_from(a_suf);
+      compression = short_be(comp_h);
+      switch (compression >> 14)
+      {
+        case PICO_DNS_POINTER:
+          while (compression >> 14 == PICO_DNS_POINTER) {
+            dns_dbg("DNS: pointer\n");
+            a_suf += sizeof(uint16_t);
+            comp_h = short_from(a_suf);
+            compression = short_be(comp_h);
+          }
+          break;
+
+        case PICO_DNS_LABEL:
+          dns_dbg("DNS: label\n");
+          a_suf = pico_dns_client_seek(a_qname);
+          break;
+
+        default:
+          dns_dbg("DNS ERROR: incorrect compression (%u) value\n", compression);
+          return;
+      }
+
+      /* Check answer suffix validity */
+      answer_suf = *(struct dns_answer_suffix *)a_suf;
+      if (short_be(answer_suf.qtype) != key->qtype || short_be(answer_suf.qclass) != key->qclass) {
+        dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(answer_suf.qtype), short_be(answer_suf.qclass));
+        a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength);
+        continue;
+      }
+
+      if (short_be(answer_suf.ttl) > PICO_DNS_MAX_TTL) {
+        dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", short_be(answer_suf.ttl), PICO_DNS_MAX_TTL);
+        a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength);
+        continue;
+      }
+
+      valid_suffix = 1;
+      break;
+    }
+
+    if (!valid_suffix) {
+       dns_dbg("DNS ERROR: invalid dns answer suffix\n");
+       return;
+    }
+
+    a_rdata = a_suf + sizeof(struct dns_answer_suffix);
+    if (key->qtype == PICO_DNS_TYPE_A) {
+      uint32_t ip_h = long_from(a_rdata);
+      dns_dbg("DNS: length %u | ip %08X\n", short_be(answer_suf.rdlength), long_be(ip_h));
+      answer = pico_zalloc(16);
+      pico_ipv4_to_string(answer, ip_h);
+      key->callback(answer, key->arg);
+    } else if (key->qtype == PICO_DNS_TYPE_PTR) {
+      pico_dns_client_reverse_label((char *) a_rdata);
+      dns_dbg("DNS: length %u | name %s\n", short_be(answer_suf.rdlength), (char *)a_rdata + 1);
+      answer = pico_zalloc(answer_suf.rdlength - 1);
+      memcpy(answer, (char *)a_rdata + 1, short_be(answer_suf.rdlength) - 1);
+      key->callback(answer, key->arg);
+    } else {
+      dns_dbg("DNS ERROR: incorrect qtype (%u)\n", key->qtype);
+      return;
+    }
+  }
+
+  if (ev == PICO_SOCK_EV_ERR) {
+    dns_dbg("DNS: socket error received\n");
+  }
+}
+
+int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg)
+{
+  char *q_hdr, *q_qname, *q_suf;
+  struct dns_message_hdr *hdr;
+  struct dns_query_suffix query_suf;
+  struct pico_dns_key *key;
+  uint16_t url_len = 0;
+  uint16_t id = 0;
+
+  if (!url || !callback) {
+    dns_dbg("DNS ERROR: NULL parameters\n");
+    pico_err = PICO_ERR_EINVAL;
+    return -1;
+  }
+
+  url_len = pico_dns_client_strlen(url);
+  /* 2 extra bytes for url_len to account for 2 extra label length octets */
+  q_hdr = pico_zalloc(sizeof(struct dns_message_hdr) + (1 + url_len + 1) + sizeof(struct dns_query_suffix));
+  if (!q_hdr) {
+    pico_err = PICO_ERR_ENOMEM;
+    return -1;
+  }
+  q_qname = q_hdr + sizeof(struct dns_message_hdr);
+  q_suf = q_qname + (1 + url_len + 1);
+
+  /* Construct query header */
+  hdr = (struct dns_message_hdr *) q_hdr;
+  do {
+    id = (uint16_t) (pico_rand() & 0xFFFFU);
+    dns_dbg("DNS: generated id %u\n", id);
+  } while (pico_dns_client_idcheck(id));
+  pico_dns_client_construct_hdr(hdr, id);
+  /* Add and manipulate domain name */
+  memcpy(q_qname + 1, url, url_len + 1);
+  pico_dns_client_label(q_qname);
+  /* Add type and class of query */
+  query_suf.qtype = short_be(PICO_DNS_TYPE_A);
+  query_suf.qclass = short_be(PICO_DNS_CLASS_IN);
+  memcpy(q_suf, &query_suf, sizeof(struct dns_query_suffix));
+  /* Create RB entry */
+  key = pico_zalloc(sizeof(struct pico_dns_key));
+  if (!key) {
+    pico_free(q_hdr);
+    pico_err = PICO_ERR_ENOMEM;
+    return -1;
+  }
+  key->q_hdr = q_hdr;
+  key->len = sizeof(struct dns_message_hdr) + (1 + url_len + 1) + sizeof(struct dns_query_suffix);
+  key->id = id;
+  key->qtype = PICO_DNS_TYPE_A;
+  key->qclass = PICO_DNS_CLASS_IN;
+  key->retrans = 1;
+
+  key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
+  key->s = NULL;
+  key->callback = callback;
+  key->arg = arg;
+  /* Send query */
+  if (pico_dns_client_send(key) < 0) {
+    pico_free(q_hdr);
+    if (key->s)
+      pico_socket_close(key->s);
+    pico_free(key);
+    pico_err = PICO_ERR_EAGAIN;
+    return -1;
+  }
+  /* Insert RB entry */
+
+  if(pico_tree_insert(&DNSTable,key)) {
+    pico_free(q_hdr);
+    pico_free(key);
+    pico_err = PICO_ERR_EAGAIN;
+    return -1; /* Element key already exists */
+  }
+
+  pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key);
+  return 0;
+}
+
+int pico_dns_client_getname(const char *ip, void (*callback)(char *, void *), void *arg)
+{
+  char *q_hdr, *q_qname, *q_suf;
+  struct dns_message_hdr *hdr;
+  struct dns_query_suffix query_suf;
+  struct pico_dns_key *key;
+  uint16_t ip_len = 0;
+  uint16_t arpa_len = 0;
+  uint16_t id = 0;
+
+  if (!ip || !callback) {
+    dns_dbg("DNS ERROR: NULL parameters\n");
+    pico_err = PICO_ERR_EINVAL;
+    return -1;
+  }
+
+  ip_len = pico_dns_client_strlen(ip);
+  arpa_len = pico_dns_client_strlen(".in-addr.arpa");
+  /* 2 extra bytes for ip_len and arpa_len to account for 2 extra length octets */
+  q_hdr = pico_zalloc(sizeof(struct dns_message_hdr) + (1 + ip_len + arpa_len + 1) + sizeof(struct dns_query_suffix));
+  if (!q_hdr) {
+    pico_err = PICO_ERR_ENOMEM;
+    return -1;
+  }
+  q_qname = q_hdr + sizeof(struct dns_message_hdr);
+  q_suf = q_qname + (1 + ip_len + arpa_len + 1);
+
+  /* Construct query header */
+  hdr = (struct dns_message_hdr *)q_hdr;
+  do {
+    id = (uint16_t) (pico_rand() & 0xFFFFU);
+    dns_dbg("DNS: generated id %u\n", id);
+  } while (pico_dns_client_idcheck(id));
+  pico_dns_client_construct_hdr(hdr, id);
+  /* Add and manipulate domain name */
+  memcpy(q_qname + 1, ip, ip_len + 1);
+  pico_dns_client_mirror(q_qname + 1);
+  memcpy(q_qname + 1 + ip_len, ".in-addr.arpa", arpa_len);
+  pico_dns_client_label(q_qname);
+  /* Add type and class of query */
+  query_suf.qtype = short_be(PICO_DNS_TYPE_PTR);
+  query_suf.qclass = short_be(PICO_DNS_CLASS_IN);
+  memcpy(q_suf, &query_suf, sizeof(struct dns_query_suffix));
+  /* Create RB entry */
+  key = pico_zalloc(sizeof(struct pico_dns_key));
+  if (!key) {
+    pico_free(q_hdr);
+    pico_err = PICO_ERR_ENOMEM;
+    return -1;
+  }
+  key->q_hdr = q_hdr;
+  key->len = sizeof(struct dns_message_hdr) + (1 + ip_len + arpa_len + 1) + sizeof(struct dns_query_suffix);
+  key->id = id;
+  key->qtype = PICO_DNS_TYPE_PTR;
+  key->qclass = PICO_DNS_CLASS_IN;
+  key->retrans = 1;
+  key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable));
+  key->s = NULL;
+  key->callback = callback;
+  key->arg = arg;
+  /* Send query */
+  if (pico_dns_client_send(key) < 0) {
+    pico_free(q_hdr);
+    if (key->s)
+      pico_socket_close(key->s);
+    pico_free(key);
+    pico_err = PICO_ERR_EAGAIN;
+    return -1;
+  }
+  /* Insert RB entry */
+
+  if(pico_tree_insert(&DNSTable,key)) {
+    pico_free(q_hdr);
+    pico_free(key);
+    pico_err = PICO_ERR_EAGAIN;
+    return -1; /* Element key already exists */
+  }
+
+  pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key);
+  return 0;
+}
+
+#ifdef PICO_DNS_CLIENT_MAIN
+int main(int argc, char *argv[])
+{
+  dns_dbg(">>>>> DNS GET ADDR\n");
+  pico_dns_client_getaddr("www.google.be");
+  dns_dbg(">>>>> DNS GET NAME\n");
+  pico_dns_client_getname("173.194.67.94");
+
+  return 0;
+}
+#endif /* PICO_DNS_CLIENT_MAIN */
+#endif /* PICO_SUPPORT_DNS_CLIENT */