text: /*
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in the
   *    documentation and/or other materials provided with the distribution.
   * 3. Neither the name of the Institute nor the names of its contributors
   *    may be used to endorse or promote products derived from this software
   *    without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   *
   * This file is part of the Contiki operating system.
   *
   */
  
  #include "contiki.h"
  #include "contiki-lib.h"
  #include "contiki-net.h"
  
  #if UIP_CONF_IPV6_RPL
  #include "contiki/rpl/rpl.h"
  #endif /* UIP_CONF_IPV6_RPL */
  
  #include <string.h>
  
  #include "tinydtls.h"
  
  #ifndef DEBUG
  #define DEBUG DEBUG_PRINT
  #endif
  #include "contiki/ip/uip-debug.h"
  
  #include "debug.h"
  #include "dtls.h"
  
  #ifdef ENABLE_POWERTRACE
  #include "powertrace.h"
  #endif
  
  #define UIP_IP_BUF   ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
  #define UIP_UDP_BUF  ((struct uip_udp_hdr *)&uip_buf[UIP_LLIPH_LEN])
  
  #define MAX_PAYLOAD_LEN 120
  
  static struct uip_udp_conn *server_conn;
  
  static dtls_context_t *dtls_context;
  
  static const unsigned char ecdsa_priv_key[] = {
  			0xD9, 0xE2, 0x70, 0x7A, 0x72, 0xDA, 0x6A, 0x05,
  			0x04, 0x99, 0x5C, 0x86, 0xED, 0xDB, 0xE3, 0xEF,
  			0xC7, 0xF1, 0xCD, 0x74, 0x83, 0x8F, 0x75, 0x70,
  			0xC8, 0x07, 0x2D, 0x0A, 0x76, 0x26, 0x1B, 0xD4};
  
  static const unsigned char ecdsa_pub_key_x[] = {
  			0xD0, 0x55, 0xEE, 0x14, 0x08, 0x4D, 0x6E, 0x06,
  			0x15, 0x59, 0x9D, 0xB5, 0x83, 0x91, 0x3E, 0x4A,
  			0x3E, 0x45, 0x26, 0xA2, 0x70, 0x4D, 0x61, 0xF2,
  			0x7A, 0x4C, 0xCF, 0xBA, 0x97, 0x58, 0xEF, 0x9A};
  
  static const unsigned char ecdsa_pub_key_y[] = {
  			0xB4, 0x18, 0xB6, 0x4A, 0xFE, 0x80, 0x30, 0xDA,
  			0x1D, 0xDC, 0xF4, 0xF4, 0x2E, 0x2F, 0x26, 0x31,
  			0xD0, 0x43, 0xB1, 0xFB, 0x03, 0xE2, 0x2F, 0x4D,
  			0x17, 0xDE, 0x43, 0xF9, 0xF9, 0xAD, 0xEE, 0x70};
  
  static int
  read_from_peer(struct dtls_context_t *ctx, 
  	       session_t *session, uint8 *data, size_t len) {
    size_t i;
    for (i = 0; i < len; i++)
      PRINTF("%c", data[i]);
  
    /* echo incoming application data */
    dtls_write(ctx, session, data, len);
    return 0;
  }
  
  static int
  send_to_peer(struct dtls_context_t *ctx, 
  	     session_t *session, uint8 *data, size_t len) {
  
    struct uip_udp_conn *conn = (struct uip_udp_conn *)dtls_get_app_data(ctx);
  
    uip_ipaddr_copy(&conn->ripaddr, &session->addr);
    conn->rport = session->port;
  
    PRINTF("send to ");
    PRINT6ADDR(&conn->ripaddr);
    PRINTF(":%u\n", uip_ntohs(conn->rport));
  
    uip_udp_packet_send(conn, data, len);
  
    /* Restore server connection to allow data from any node */
    memset(&conn->ripaddr, 0, sizeof(conn->ripaddr));
    memset(&conn->rport, 0, sizeof(conn->rport));
  
    return len;
  }
  
  #ifdef DTLS_PSK
  /* This function is the "key store" for tinyDTLS. It is called to
   * retrieve a key for the given identity within this particular
   * session. */
  static int
  get_psk_info(struct dtls_context_t *ctx, const session_t *session,
  	     dtls_credentials_type_t type,
  	     const unsigned char *id, size_t id_len,
  	     unsigned char *result, size_t result_length) {
  
    struct keymap_t {
      unsigned char *id;
      size_t id_length;
      unsigned char *key;
      size_t key_length;
    } psk[3] = {
      { (unsigned char *)"Client_identity", 15,
        (unsigned char *)"secretPSK", 9 },
      { (unsigned char *)"default identity", 16,
        (unsigned char *)"\x11\x22\x33", 3 },
      { (unsigned char *)"\0", 2,
        (unsigned char *)"", 1 }
    };
  
    if (type != DTLS_PSK_KEY) {
      return 0;
    }
  
    if (id) {
      int i;
      for (i = 0; i < sizeof(psk)/sizeof(struct keymap_t); i++) {
        if (id_len == psk[i].id_length && memcmp(id, psk[i].id, id_len) == 0) {
  	if (result_length < psk[i].key_length) {
  	  dtls_warn("buffer too small for PSK");
  	  return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
  	}
  
  	memcpy(result, psk[i].key, psk[i].key_length);
  	return psk[i].key_length;
        }
      }
    }
  
    return dtls_alert_fatal_create(DTLS_ALERT_DECRYPT_ERROR);
  }
  #endif /* DTLS_PSK */
  
  #ifdef DTLS_ECC
  static int
  get_ecdsa_key(struct dtls_context_t *ctx,
  	      const session_t *session,
  	      const dtls_ecdsa_key_t **result) {
    static const dtls_ecdsa_key_t ecdsa_key = {
      .curve = DTLS_ECDH_CURVE_SECP256R1,
      .priv_key = ecdsa_priv_key,
      .pub_key_x = ecdsa_pub_key_x,
      .pub_key_y = ecdsa_pub_key_y
    };
  
    *result = &ecdsa_key;
    return 0;
  }
  
  static int
  verify_ecdsa_key(struct dtls_context_t *ctx,
  		 const session_t *session,
  		 const unsigned char *other_pub_x,
  		 const unsigned char *other_pub_y,
  		 size_t key_size) {
    return 0;
  }
  #endif /* DTLS_ECC */
  
  PROCESS(udp_server_process, "UDP server process");
  AUTOSTART_PROCESSES(&udp_server_process);
  /*---------------------------------------------------------------------------*/
  static void
  dtls_handle_read(dtls_context_t *ctx) {
    session_t session;
  
    if(uip_newdata()) {
      uip_ipaddr_copy(&session.addr, &UIP_IP_BUF->srcipaddr);
      session.port = UIP_UDP_BUF->srcport;
      session.size = sizeof(session.addr) + sizeof(session.port);
      
      dtls_handle_message(ctx, &session, uip_appdata, uip_datalen());
    }
  }
  /*---------------------------------------------------------------------------*/
  static void
  print_local_addresses(void)
  {
    int i;
    uint8_t state;
  
    PRINTF("Server IPv6 addresses: \n");
    for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
      state = uip_ds6_if.addr_list[i].state;
      if(uip_ds6_if.addr_list[i].isused &&
         (state == ADDR_TENTATIVE || state == ADDR_PREFERRED)) {
        PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr);
        PRINTF("\n");
      }
    }
  }
  
  #if 0
  static void
  create_rpl_dag(uip_ipaddr_t *ipaddr)
  {
    struct uip_ds6_addr *root_if;
  
    root_if = uip_ds6_addr_lookup(ipaddr);
    if(root_if != NULL) {
      rpl_dag_t *dag;
      uip_ipaddr_t prefix;
      
      rpl_set_root(RPL_DEFAULT_INSTANCE, ipaddr);
      dag = rpl_get_any_dag();
      uip_ip6addr(&prefix, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);
      rpl_set_prefix(dag, &prefix, 64);
      PRINTF("created a new RPL dag\n");
    } else {
      PRINTF("failed to create a new RPL DAG\n");
    }
  }
  #endif
  
  void
  init_dtls() {
    static dtls_handler_t cb = {
      .write = send_to_peer,
      .read  = read_from_peer,
      .event = NULL,
  #ifdef DTLS_PSK
      .get_psk_info = get_psk_info,
  #endif /* DTLS_PSK */
  #ifdef DTLS_ECC
      .get_ecdsa_key = get_ecdsa_key,
      .verify_ecdsa_key = verify_ecdsa_key
  #endif /* DTLS_ECC */
    };
  #if 0
    uip_ipaddr_t ipaddr;
    /* struct uip_ds6_addr *root_if; */
  #endif /* UIP_CONF_ROUTER */
  
    PRINTF("DTLS server started\n");
  
  #if 0  /* TEST */
    memset(&tmp_addr, 0, sizeof(rimeaddr_t));
    if(get_eui64_from_eeprom(tmp_addr.u8));
  #if NETSTACK_CONF_WITH_IPV6
    memcpy(&uip_lladdr.addr, &tmp_addr.u8, 8);
  #endif
  #endif /* TEST */
  
  #if 0
  /*   uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0); */
  /*   uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); */
  /*   uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); */
  
  /*   create_rpl_dag(&ipaddr); */
  /* #else */
    /* uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); */
  
    uip_ip6addr(&ipaddr, 0xaaaa, 0,0,0,0x0200,0,0,0x0003);
    uip_ds6_addr_add(&ipaddr, 0, ADDR_MANUAL);
  
    create_rpl_dag(&ipaddr);
  #endif /* UIP_CONF_ROUTER */
  
    server_conn = udp_new(NULL, 0, NULL);
    udp_bind(server_conn, UIP_HTONS(20220));
  
    dtls_set_log_level(DTLS_LOG_DEBUG);
  
    dtls_context = dtls_new_context(server_conn);
    if (dtls_context)
      dtls_set_handler(dtls_context, &cb);
  }
  
  /*---------------------------------------------------------------------------*/
  PROCESS_THREAD(udp_server_process, ev, data)
  {
    PROCESS_BEGIN();
  
    dtls_init();
    init_dtls();
  
    print_local_addresses();
  
    if (!dtls_context) {
      dtls_emerg("cannot create context\n");
      PROCESS_EXIT();
    }
  
  #ifdef ENABLE_POWERTRACE
    powertrace_start(CLOCK_SECOND * 2); 
  #endif
  
    while(1) {
      PROCESS_WAIT_EVENT();
      if(ev == tcpip_event) {
        dtls_handle_read(dtls_context);
      }
  #if 0
      if (bytes_read > 0) {
        /* dtls_handle_message(dtls_context, &the_session, readbuf, bytes_read); */
        read_from_peer(dtls_context, &the_session, readbuf, bytes_read);
      }
      dtls_handle_message(ctx, &session, uip_appdata, bytes_read);
  #endif
    }
  
    PROCESS_END();
  }
  /*---------------------------------------------------------------------------*/
  