ikev2: add support for custom ipsec-over-udp port
[vpp.git] / src / plugins / igmp / igmp_input.c
index d4563bf..1858a1b 100644 (file)
@@ -61,7 +61,7 @@ typedef struct
 {
   u32 next_index;
   u32 sw_if_index;
-
+  u32 len;
   u8 packet_data[64];
 } igmp_input_trace_t;
 
@@ -100,10 +100,12 @@ format_igmp_parse_query_trace (u8 * s, va_list * va)
   CLIB_UNUSED (vlib_node_t * node) = va_arg (*va, vlib_node_t *);
   igmp_input_trace_t *t = va_arg (*va, igmp_input_trace_t *);
 
-  s = format (s, "sw_if_index %u next-input %u",
-             t->sw_if_index, t->next_index);
+  s = format (s, "sw_if_index %u next-input %u len %u",
+             t->sw_if_index, t->next_index, t->len);
   s = format (s, "\n%U", format_igmp_query_v3, t->packet_data,
              sizeof (t->packet_data));
+  s = format (s, "\n%U", format_hex_bytes,
+             t->packet_data, sizeof (t->packet_data));
   return s;
 }
 
@@ -203,8 +205,9 @@ igmp_input (vlib_main_t * vm, vlib_node_runtime_t * node,
              tr = vlib_add_trace (vm, node, b, sizeof (*tr));
              tr->next_index = next;
              tr->sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
-             clib_memcpy (tr->packet_data, vlib_buffer_get_current (b),
-                          sizeof (tr->packet_data));
+             tr->len = vlib_buffer_length_in_chain (vm, b);
+             clib_memcpy_fast (tr->packet_data, vlib_buffer_get_current (b),
+                               sizeof (tr->packet_data));
            }
 
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
@@ -259,8 +262,8 @@ igmp_parse_query (vlib_main_t * vm, vlib_node_runtime_t * node,
        {
          igmp_membership_query_v3_t *igmp;
          igmp_query_args_t *args;
+         u32 bi, next, len;
          vlib_buffer_t *b;
-         u32 bi, next;
 
          next = IGMP_PARSE_QUERY_NEXT_DROP;
          bi = from[0];
@@ -273,6 +276,7 @@ igmp_parse_query (vlib_main_t * vm, vlib_node_runtime_t * node,
          b = vlib_get_buffer (vm, bi);
          igmp = vlib_buffer_get_current (b);
          ASSERT (igmp->header.type == IGMP_TYPE_membership_query);
+         len = igmp_membership_query_v3_length (igmp);
 
          if (node->flags & VLIB_NODE_FLAG_TRACE)
            {
@@ -280,23 +284,37 @@ igmp_parse_query (vlib_main_t * vm, vlib_node_runtime_t * node,
              tr = vlib_add_trace (vm, node, b, sizeof (*tr));
              tr->next_index = next;
              tr->sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
-             clib_memcpy (tr->packet_data, vlib_buffer_get_current (b),
-                          sizeof (tr->packet_data));
+             tr->len = len;
+             clib_memcpy_fast (tr->packet_data, vlib_buffer_get_current (b),
+                               sizeof (tr->packet_data));
            }
 
          /*
-          * copy the contents of the query, and the interface, over
-          * to the main thread for processing
+          * validate that the length on the packet on the wire  corresponds
+          * to at least the length of the calculated v3 query.
+          * If there's extra, then it will be ignored.
           */
-         vlib_buffer_advance (b, -sizeof (u32));
-         args = vlib_buffer_get_current (b);
-         args->sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
-
-         vl_api_rpc_call_main_thread (igmp_handle_query,
-                                      (u8 *) args,
-                                      sizeof (*args) +
-                                      igmp_membership_query_v3_length
-                                      (igmp));
+         if (vlib_buffer_length_in_chain (vm, b) >= len)
+           {
+             /*
+              * copy the contents of the query, and the interface, over
+              * to the main thread for processing
+              */
+             vlib_buffer_advance (b, -sizeof (u32));
+             args = vlib_buffer_get_current (b);
+             args->sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
+
+             vl_api_rpc_call_main_thread (igmp_handle_query,
+                                          (u8 *) args, sizeof (*args) + len);
+           }
+         else
+           {
+             /*
+              * else a packet that is reporting more sources than it really
+              * has; bin it
+              */
+             b->error = node->errors[IGMP_ERROR_BAD_LENGTH];
+           }
 
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
                                           n_left_to_next, bi, next);
@@ -351,7 +369,7 @@ igmp_parse_report (vlib_main_t * vm, vlib_node_runtime_t * node,
        {
          igmp_membership_report_v3_t *igmp;
          igmp_report_args_t *args;
-         u32 bi, next;
+         u32 bi, next, len;
          vlib_buffer_t *b;
 
          next = IGMP_PARSE_REPORT_NEXT_DROP;
@@ -368,6 +386,7 @@ igmp_parse_report (vlib_main_t * vm, vlib_node_runtime_t * node,
          error = IGMP_ERROR_NONE;
          b->error = error_node->errors[error];
          igmp = vlib_buffer_get_current (b);
+         len = igmp_membership_report_v3_length (igmp);
 
          ASSERT (igmp->header.type == IGMP_TYPE_membership_report_v3);
 
@@ -376,24 +395,37 @@ igmp_parse_report (vlib_main_t * vm, vlib_node_runtime_t * node,
              igmp_input_trace_t *tr;
              tr = vlib_add_trace (vm, node, b, sizeof (*tr));
              tr->next_index = next;
+             tr->len = len;
              tr->sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
-             clib_memcpy (tr->packet_data, vlib_buffer_get_current (b),
-                          sizeof (tr->packet_data));
+             clib_memcpy_fast (tr->packet_data, vlib_buffer_get_current (b),
+                               sizeof (tr->packet_data));
            }
 
          /*
-          * copy the contents of the query, and the interface, over
-          * to the main thread for processing
+          * validate that the length on the packet on the wire
+          * corresponds to the length on the calculated v3 query
           */
-         vlib_buffer_advance (b, -sizeof (u32));
-         args = vlib_buffer_get_current (b);
-         args->sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
-
-         vl_api_rpc_call_main_thread (igmp_handle_report,
-                                      (u8 *) args,
-                                      sizeof (*args) +
-                                      igmp_membership_report_v3_length
-                                      (igmp));
+         if (vlib_buffer_length_in_chain (vm, b) >= len)
+           {
+             /*
+              * copy the contents of the query, and the interface, over
+              * to the main thread for processing
+              */
+             vlib_buffer_advance (b, -sizeof (u32));
+             args = vlib_buffer_get_current (b);
+             args->sw_if_index = vnet_buffer (b)->sw_if_index[VLIB_RX];
+
+             vl_api_rpc_call_main_thread (igmp_handle_report,
+                                          (u8 *) args, sizeof (*args) + len);
+           }
+         else
+           {
+             /*
+              * this is a packet with more groups/sources than the
+              * header reports. bin it
+              */
+             b->error = node->errors[IGMP_ERROR_BAD_LENGTH];
+           }
 
          vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
                                           n_left_to_next, bi, next);
@@ -427,19 +459,19 @@ VLIB_REGISTER_NODE (igmp_parse_report_node) =
 static clib_error_t *
 igmp_input_init (vlib_main_t * vm)
 {
-  clib_error_t *error;
-
-  if ((error = vlib_call_init_function (vm, igmp_init)))
-    return error;
-
   ip4_register_protocol (IP_PROTOCOL_IGMP, igmp_input_node.index);
 
   IGMP_DBG ("input-initialized");
 
-  return (error);
+  return (0);
 }
 
-VLIB_INIT_FUNCTION (igmp_input_init);
+/* *INDENT-OFF* */
+VLIB_INIT_FUNCTION (igmp_input_init) =
+{
+  .runs_after = VLIB_INITS("igmp_init"),
+};
+/* *INDENT-ON* */
 
 /*
  * fd.io coding-style-patch-verification: ON