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)