From: Ben Pfaff Date: Wed, 17 Dec 2008 00:38:01 +0000 (-0800) Subject: New functions for verify OpenFlow message types and lengths. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=dce4ee070a8f06457d40f1e2187f475de9f96f5f;p=openvswitch New functions for verify OpenFlow message types and lengths. --- diff --git a/lib/vconn.c b/lib/vconn.c index 6b0bc71a..41c1eefa 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -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) diff --git a/lib/vconn.h b/lib/vconn.h index 3baaea6b..a01d93db 100644 --- a/lib/vconn.h +++ b/lib/vconn.h @@ -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 */