Update DHCPv6 DUID code and fix coverity warnings

- Generate client DUID only when DHCPv6 PD feature is enabled
- Change client DUID type from DUID-LLT to DUID-LL
- Fix coverity warnings

Change-Id: I20e518fc9a1c5f3f7ea9add7e7e03a487c99e978
Signed-off-by: Juraj Sloboda <jsloboda@cisco.com>
diff --git a/src/vnet/dhcp/dhcp.api b/src/vnet/dhcp/dhcp.api
index 82c03fc..ab0f7b6 100644
--- a/src/vnet/dhcp/dhcp.api
+++ b/src/vnet/dhcp/dhcp.api
@@ -186,6 +186,18 @@
   vl_api_dhcp_server_t servers[count];
 };
 
+/** \brief Set DHCPv6 DUID-LL
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+    @param duid_ll - DUID-LL binary string
+*/
+autoreply define dhcp6_duid_ll_set
+{
+  u32 client_index;
+  u32 context;
+  u8 duid_ll[10];
+};
+
 /** \brief Enable/disable listening on DHCPv6 client port
     @param client_index - opaque cookie to identify the sender
     @param context - sender context, to match reply w/ request
diff --git a/src/vnet/dhcp/dhcp6_pd_client_cp.c b/src/vnet/dhcp/dhcp6_pd_client_cp.c
index ecb85e1..a2a0618 100644
--- a/src/vnet/dhcp/dhcp6_pd_client_cp.c
+++ b/src/vnet/dhcp/dhcp6_pd_client_cp.c
@@ -658,7 +658,7 @@
       clib_warning ("Prefix length is bigger that 64 bits");
       return 1;
     }
-  mask = (1 << (64 - prefix->prefix_length)) - 1;
+  mask = ((u64) 1 << (64 - prefix->prefix_length)) - 1;
   addr0 &= mask;
   pref = clib_host_to_net_u64 (prefix->prefix.as_u64[0]);
   pref &= ~mask;
@@ -871,10 +871,17 @@
 {
 
   ip6_address_with_prefix_main_t *apm = &ip6_address_with_prefix_main;
+  vnet_main_t *vnm = vnet_get_main ();
   ip6_address_info_t *address_info;
   u32 prefix_group_index;
   u32 n;
 
+  if (!vnet_sw_interface_is_api_valid (vnm, sw_if_index))
+    {
+      clib_warning ("Invalid sw_if_index");
+      return VNET_API_ERROR_INVALID_VALUE;
+    }
+
   if (prefix_group != 0 && prefix_group[0] != '\0')
     {
       if (strnlen ((const char *) prefix_group, 64) == 64)
@@ -927,12 +934,9 @@
   u8 prefix_length;
   int rv = 0;
 
+  VALIDATE_SW_IF_INDEX (mp);
+
   sw_if_index = ntohl (mp->sw_if_index);
-  if (!vnet_sw_if_index_is_api_valid (sw_if_index))
-    {
-      rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
-      goto bad_sw_if_index;
-    }
 
   memcpy (address.as_u8, mp->address, 16);
   prefix_length = mp->prefix_length;
diff --git a/src/vnet/dhcp/dhcp6_pd_client_dp.c b/src/vnet/dhcp/dhcp6_pd_client_dp.c
index c14a311..b2b8f88 100644
--- a/src/vnet/dhcp/dhcp6_pd_client_dp.c
+++ b/src/vnet/dhcp/dhcp6_pd_client_dp.c
@@ -112,13 +112,12 @@
 	       {
 	       u16 duid_type;
 	       u16 hardware_type;
-	       u32 time;
 	       u8 lla[6];
 	       });
-  char bin_string[14];
-} dhcpv6_duid_string_t;
+  char bin_string[10];
+} dhcpv6_duid_ll_string_t;
 
-static dhcpv6_duid_string_t client_duid;
+static dhcpv6_duid_ll_string_t client_duid;
 #define CLIENT_DUID_LENGTH sizeof (client_duid)
 #define DHCPV6_CLIENT_IAID 1
 
@@ -409,9 +408,20 @@
 			  discard = 1;
 			}
 		      else
-			report.server_index =
-			  server_index_get_or_create (option->data,
-						      ntohs (option->length));
+			{
+			  u16 ol = ntohs (option->length);
+			  if (ol - 2 /* 2 byte DUID type code */  > 128)
+			    {
+			      clib_warning
+				("Server DUID (without type code) is longer than 128 octets");
+			      discard = 1;
+			    }
+			  else
+			    {
+			      report.server_index =
+				server_index_get_or_create (option->data, ol);
+			    }
+			}
 		    }
 		  else if (oo == DHCPV6_OPTION_PREFERENCE)
 		    {
@@ -1049,37 +1059,29 @@
 }
 
 void
-dhcp6_clients_enable_disable (u8 enable)
+vl_api_dhcp6_duid_ll_set_t_handler (vl_api_dhcp6_duid_ll_set_t * mp)
 {
-  vlib_main_t *vm = vlib_get_main ();
-
-  if (enable)
-    udp_register_dst_port (vm, UDP_DST_PORT_dhcpv6_to_client,
-			   dhcpv6_pd_client_node.index, 0 /* is_ip6 */ );
-  else
-    udp_unregister_dst_port (vm, UDP_DST_PORT_dhcpv6_to_client,
-			     0 /* is_ip6 */ );
-}
-
-void
-  vl_api_dhcp6_clients_enable_disable_t_handler
-  (vl_api_dhcp6_clients_enable_disable_t * mp)
-{
-  vl_api_dhcp6_clients_enable_disable_reply_t *rmp;
+  vl_api_dhcp6_duid_ll_set_reply_t *rmp;
+  dhcpv6_duid_ll_string_t *duid;
   int rv = 0;
 
-  dhcp6_clients_enable_disable (mp->enable);
+  duid = (dhcpv6_duid_ll_string_t *) mp->duid_ll;
+  if (duid->duid_type != htonl (DHCPV6_DUID_LL))
+    {
+      rv = VNET_API_ERROR_INVALID_VALUE;
+      goto reply;
+    }
+  clib_memcpy (&client_duid, &duid, sizeof (client_duid));
 
-  REPLY_MACRO (VL_API_WANT_DHCP6_PD_REPLY_EVENTS_REPLY);
+reply:
+  REPLY_MACRO (VL_API_DHCP6_DUID_LL_SET_REPLY);
 }
 
 static void
-genereate_client_duid (void)
+generate_client_duid (void)
 {
-  client_duid.duid_type = htons (DHCPV6_DUID_LLT);
+  client_duid.duid_type = htons (DHCPV6_DUID_LL);
   client_duid.hardware_type = htons (1);
-  u32 time_since_2000 = (u32) time (0) - 946684800;
-  client_duid.time = htonl (time_since_2000);
 
   vnet_main_t *vnm = vnet_get_main ();
   vnet_interface_main_t *im = &vnm->interface_main;
@@ -1112,6 +1114,35 @@
     }
 }
 
+void
+dhcp6_clients_enable_disable (u8 enable)
+{
+  vlib_main_t *vm = vlib_get_main ();
+
+  if (enable)
+    {
+      if (client_duid.duid_type == 0)
+	generate_client_duid ();
+      udp_register_dst_port (vm, UDP_DST_PORT_dhcpv6_to_client,
+			     dhcpv6_pd_client_node.index, 0 /* is_ip6 */ );
+    }
+  else
+    udp_unregister_dst_port (vm, UDP_DST_PORT_dhcpv6_to_client,
+			     0 /* is_ip6 */ );
+}
+
+void
+  vl_api_dhcp6_clients_enable_disable_t_handler
+  (vl_api_dhcp6_clients_enable_disable_t * mp)
+{
+  vl_api_dhcp6_clients_enable_disable_reply_t *rmp;
+  int rv = 0;
+
+  dhcp6_clients_enable_disable (mp->enable);
+
+  REPLY_MACRO (VL_API_WANT_DHCP6_PD_REPLY_EVENTS_REPLY);
+}
+
 static clib_error_t *
 dhcp6_pd_client_init (vlib_main_t * vm)
 {
@@ -1124,9 +1155,6 @@
 
   cm->seed = 0xdeaddabe;
 
-  // TODO: should be stored in non-volatile memory
-  genereate_client_duid ();
-
   return 0;
 }
 
diff --git a/src/vnet/dhcp/dhcp6_pd_client_dp.h b/src/vnet/dhcp/dhcp6_pd_client_dp.h
index eec8fe8..ef69f19 100644
--- a/src/vnet/dhcp/dhcp6_pd_client_dp.h
+++ b/src/vnet/dhcp/dhcp6_pd_client_dp.h
@@ -59,6 +59,7 @@
 void
   vl_api_dhcp6_clients_enable_disable_t_handler
   (vl_api_dhcp6_clients_enable_disable_t * mp);
+void vl_api_dhcp6_duid_ll_set_t_handler (vl_api_dhcp6_duid_ll_set_t * mp);
 
 extern vlib_node_registration_t dhcp6_pd_reply_process_node;
 
diff --git a/src/vnet/dhcp/dhcp_api.c b/src/vnet/dhcp/dhcp_api.c
index 5aed4c0..4e2ed86 100644
--- a/src/vnet/dhcp/dhcp_api.c
+++ b/src/vnet/dhcp/dhcp_api.c
@@ -53,7 +53,8 @@
 _(DHCP_CLIENT_DUMP, dhcp_client_dump)             \
 _(WANT_DHCP6_PD_REPLY_EVENTS, want_dhcp6_pd_reply_events)               \
 _(DHCP6_PD_SEND_CLIENT_MESSAGE, dhcp6_pd_send_client_message)           \
-_(DHCP6_CLIENTS_ENABLE_DISABLE, dhcp6_clients_enable_disable)
+_(DHCP6_CLIENTS_ENABLE_DISABLE, dhcp6_clients_enable_disable)           \
+_(DHCP6_DUID_LL_SET, dhcp6_duid_ll_set)
 
 
 static void