SCTP: API to delete a sub-connection

This patch adds an API to delete a sub-connection following a SRC/DST IP
mapping as required by the RFC4960.

Change-Id: I7673dd07352557442ffeed6c6c00da274b24953d
Signed-off-by: Marco Varlese <marco.varlese@suse.com>
diff --git a/src/vnet/sctp/sctp.api b/src/vnet/sctp/sctp.api
index f2c48d6..6253c95 100644
--- a/src/vnet/sctp/sctp.api
+++ b/src/vnet/sctp/sctp.api
@@ -34,3 +34,11 @@
     u8 dst_address[16];
  };
  
+autoreply define sctp_del_src_dst_connection {
+    u32 client_index;
+    u32 context;
+    u8 is_ipv6;
+    u32 vrf_id;
+    u8 src_address[16];
+    u8 dst_address[16];
+ };
\ No newline at end of file
diff --git a/src/vnet/sctp/sctp.c b/src/vnet/sctp/sctp.c
index b1186a6..cc70f7c 100644
--- a/src/vnet/sctp/sctp.c
+++ b/src/vnet/sctp/sctp.c
@@ -306,6 +306,40 @@
 }
 
 u8
+sctp_sub_connection_del_ip4 (ip4_address_t * lcl_addr,
+			     ip4_address_t * rmt_addr)
+{
+  sctp_main_t *sctp_main = vnet_get_sctp_main ();
+
+  u32 thread_idx = vlib_get_thread_index ();
+  u8 i;
+
+  ASSERT (thread_idx == 0);
+
+  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
+    {
+      sctp_connection_t *sctp_conn = sctp_main->connections[thread_idx];
+      sctp_sub_connection_t *sub_conn =
+	&sctp_main->connections[thread_idx]->sub_conn[i];
+      ip46_address_t *lcl_ip =
+	&sctp_main->connections[thread_idx]->sub_conn[i].connection.lcl_ip;
+      ip46_address_t *rmt_ip =
+	&sctp_main->connections[thread_idx]->sub_conn[i].connection.rmt_ip;
+
+      if (!sub_conn->connection.is_ip4)
+	continue;
+      if (lcl_ip->ip4.as_u32 == lcl_addr->as_u32 &&
+	  rmt_ip->ip4.as_u32 == rmt_addr->as_u32)
+	{
+	  sub_conn->state = SCTP_SUBCONN_STATE_DOWN;
+	  sctp_conn->forming_association_changed = 1;
+	  break;
+	}
+    }
+  return SCTP_ERROR_NONE;
+}
+
+u8
 sctp_sub_connection_add_ip6 (vlib_main_t * vm,
 			     ip6_address_t * lcl_addr,
 			     ip6_address_t * rmt_addr)
@@ -328,6 +362,42 @@
   return SCTP_ERROR_NONE;
 }
 
+u8
+sctp_sub_connection_del_ip6 (ip6_address_t * lcl_addr,
+			     ip6_address_t * rmt_addr)
+{
+  sctp_main_t *sctp_main = vnet_get_sctp_main ();
+
+  u32 thread_idx = vlib_get_thread_index ();
+  u8 i;
+
+  ASSERT (thread_idx == 0);
+
+  for (i = 0; i < MAX_SCTP_CONNECTIONS; i++)
+    {
+      sctp_connection_t *sctp_conn = sctp_main->connections[thread_idx];
+      sctp_sub_connection_t *sub_conn =
+	&sctp_main->connections[thread_idx]->sub_conn[i];
+      ip46_address_t *lcl_ip =
+	&sctp_main->connections[thread_idx]->sub_conn[i].connection.lcl_ip;
+      ip46_address_t *rmt_ip =
+	&sctp_main->connections[thread_idx]->sub_conn[i].connection.rmt_ip;
+
+      if (!sub_conn->connection.is_ip4)
+	continue;
+      if ((lcl_ip->ip6.as_u64[0] == lcl_addr->as_u64[0]
+	   && lcl_ip->ip6.as_u64[1] == lcl_addr->as_u64[1])
+	  && (rmt_ip->ip6.as_u64[0] == rmt_addr->as_u64[0]
+	      && rmt_ip->ip6.as_u64[1] == rmt_addr->as_u64[1]))
+	{
+	  sub_conn->state = SCTP_SUBCONN_STATE_DOWN;
+	  sctp_conn->forming_association_changed = 1;
+	  break;
+	}
+    }
+  return SCTP_ERROR_NONE;
+}
+
 sctp_connection_t *
 sctp_connection_new (u8 thread_index)
 {
diff --git a/src/vnet/sctp/sctp.h b/src/vnet/sctp/sctp.h
index 487ff9e..9f17e53 100644
--- a/src/vnet/sctp/sctp.h
+++ b/src/vnet/sctp/sctp.h
@@ -254,6 +254,14 @@
 			     ip6_address_t * lcl_addr,
 			     ip6_address_t * rmt_addr);
 
+u8
+sctp_sub_connection_del_ip4 (ip4_address_t * lcl_addr,
+			     ip4_address_t * rmt_addr);
+
+u8
+sctp_sub_connection_del_ip6 (ip6_address_t * lcl_addr,
+			     ip6_address_t * rmt_addr);
+
 void sctp_connection_close (sctp_connection_t * sctp_conn);
 void sctp_connection_cleanup (sctp_connection_t * sctp_conn);
 void sctp_connection_del (sctp_connection_t * sctp_conn);
diff --git a/src/vnet/sctp/sctp_api.c b/src/vnet/sctp/sctp_api.c
index 2c1b072..6aac77d 100644
--- a/src/vnet/sctp/sctp_api.c
+++ b/src/vnet/sctp/sctp_api.c
@@ -40,8 +40,9 @@
 
 #include <vlibapi/api_helper_macros.h>
 
-#define foreach_sctp_api_msg                                     \
-_(SCTP_ADD_SRC_DST_CONNECTION, sctp_add_src_dst_connection)
+#define foreach_sctp_api_msg                                    \
+_(SCTP_ADD_SRC_DST_CONNECTION, sctp_add_src_dst_connection)		\
+_(SCTP_DEL_SRC_DST_CONNECTION, sctp_del_src_dst_connection)
 
 static void
   vl_api_sctp_add_src_dst_connection_t_handler
@@ -63,6 +64,23 @@
   REPLY_MACRO (VL_API_SCTP_ADD_SRC_DST_CONNECTION_REPLY);
 }
 
+static void
+  vl_api_sctp_del_src_dst_connection_t_handler
+  (vl_api_sctp_del_src_dst_connection_t * mp)
+{
+  vl_api_sctp_del_src_dst_connection_reply_t *rmp;
+  int rv;
+
+  if (mp->is_ipv6)
+    rv = sctp_sub_connection_del_ip6
+      ((ip6_address_t *) mp->src_address, (ip6_address_t *) mp->dst_address);
+  else
+    rv = sctp_sub_connection_del_ip4
+      ((ip4_address_t *) mp->src_address, (ip4_address_t *) mp->dst_address);
+
+  REPLY_MACRO (VL_API_SCTP_ADD_SRC_DST_CONNECTION_REPLY);
+}
+
 #define vl_msg_name_crc_list
 #include <vnet/sctp/sctp.api.h>
 #undef vl_msg_name_crc_list