New functions for verify OpenFlow message types and lengths.
authorBen Pfaff <blp@nicira.com>
Wed, 17 Dec 2008 00:38:01 +0000 (16:38 -0800)
committerBen Pfaff <blp@nicira.com>
Wed, 17 Dec 2008 00:57:44 +0000 (16:57 -0800)
lib/vconn.c
lib/vconn.h

index 6b0bc71a61f88a7ca5a32a93b0d0d03dd5e1f9e6..41c1eefacdb646d61012aedfa1770a115d6f3991 100644 (file)
@@ -906,6 +906,89 @@ make_echo_reply(const struct ofp_header *rq)
     return out;
 }
 
+static int
+check_message_type(uint8_t got_type, uint8_t want_type) 
+{
+    if (got_type != want_type) {
+        char *want_type_name = ofp_message_type_to_string(want_type);
+        char *got_type_name = ofp_message_type_to_string(got_type);
+        VLOG_WARN("received bad message type %s (expected %s)",
+                  got_type_name, want_type_name);
+        free(want_type_name);
+        free(got_type_name);
+        return false;
+    }
+    return true;
+}
+
+/* Checks that 'msg' has type 'type' and that it is exactly 'size' bytes long.
+ * Returns 0 if the checks pass, otherwise EINVAL. */
+int
+check_ofp_message(const struct ofp_header *msg, uint8_t type, size_t size)
+{
+    size_t got_size;
+
+    if (!check_message_type(msg->type, type)) {
+        return EINVAL;
+    }
+
+    got_size = ntohs(msg->length);
+    if (got_size != size) {
+        char *type_name = ofp_message_type_to_string(type);
+        VLOG_WARN("received %s message of length %"PRIu16" (expected %zu)",
+                  type_name, got_size, size);
+        free(type_name);
+        return EINVAL;
+    }
+
+    return 0;
+}
+
+/* Checks that 'msg' has type 'type' and that 'msg' is 'size' plus a
+ * nonnegative integer multiple of 'array_elt_size' bytes long.  Returns 0 if
+ * the checks pass, otherwise EINVAL.
+ *
+ * If 'n_array_elts' is nonnull, then '*n_array_elts' is set to the number of
+ * 'array_elt_size' blocks in 'msg' past the first 'min_size' bytes, when
+ * successful. */
+int
+check_ofp_message_array(const struct ofp_header *msg, uint8_t type,
+                        size_t min_size, size_t array_elt_size,
+                        size_t *n_array_elts)
+{
+    size_t got_size;
+
+    assert(array_elt_size);
+
+    if (!check_message_type(msg->type, type)) {
+        return EINVAL;
+    }
+
+    got_size = ntohs(msg->length);
+    if (got_size < min_size) {
+        char *type_name = ofp_message_type_to_string(type);
+        VLOG_WARN("received %s message of length %"PRIu16" "
+                  "(expected at least %zu)",
+                  type_name, got_size, min_size);
+        free(type_name);
+        return EINVAL;
+    }
+    if ((got_size - min_size) % array_elt_size) {
+        char *type_name = ofp_message_type_to_string(type);
+        VLOG_WARN("received %s message of bad length %"PRIu16": the "
+                  "excess over %zu (%zu) is not evenly divisible by %zu "
+                  "(remainder is %zu)",
+                  type_name, got_size, min_size, got_size - min_size,
+                  array_elt_size, (got_size - min_size) % array_elt_size);
+        free(type_name);
+        return EINVAL;
+    }
+    if (n_array_elts) {
+        *n_array_elts = (got_size - min_size) / array_elt_size;
+    }
+    return 0;
+}
+
 void
 vconn_init(struct vconn *vconn, struct vconn_class *class, int connect_status,
            uint32_t ip, const char *name, bool reconnectable)
index 3baaea6bc58679feddb13424956753b926b57841..a01d93db52e33553b72e237b4d38dee8d6613277 100644 (file)
@@ -94,5 +94,9 @@ struct ofpbuf *make_unbuffered_packet_out(const struct ofpbuf *packet,
                                           uint16_t in_port, uint16_t out_port);
 struct ofpbuf *make_echo_request(void);
 struct ofpbuf *make_echo_reply(const struct ofp_header *rq);
+int check_ofp_message(const struct ofp_header *, uint8_t type, size_t size);
+int check_ofp_message_array(const struct ofp_header *, uint8_t type,
+                            size_t size, size_t array_elt_size,
+                            size_t *n_array_elts);
 
 #endif /* vconn.h */