ovs-vsctl: Prevent double-free when retrying a transaction
[sliver-openvswitch.git] / lib / ofp-util.c
index fd54a03..99e5943 100644 (file)
@@ -125,14 +125,14 @@ put_openflow_xid(size_t openflow_len, uint8_t type, uint32_t xid,
 /* Updates the 'length' field of the OpenFlow message in 'buffer' to
  * 'buffer->size'. */
 void
-update_openflow_length(struct ofpbuf *buffer) 
+update_openflow_length(struct ofpbuf *buffer)
 {
     struct ofp_header *oh = ofpbuf_at_assert(buffer, 0, sizeof *oh);
-    oh->length = htons(buffer->size); 
+    oh->length = htons(buffer->size);
 }
 
 struct ofpbuf *
-make_flow_mod(uint16_t command, const flow_t *flow, size_t actions_len)
+make_flow_mod(uint16_t command, const struct flow *flow, size_t actions_len)
 {
     struct ofp_flow_mod *ofm;
     size_t size = sizeof *ofm + actions_len;
@@ -161,7 +161,7 @@ make_flow_mod(uint16_t command, const flow_t *flow, size_t actions_len)
 }
 
 struct ofpbuf *
-make_add_flow(const flow_t *flow, uint32_t buffer_id,
+make_add_flow(const struct flow *flow, uint32_t buffer_id,
               uint16_t idle_timeout, size_t actions_len)
 {
     struct ofpbuf *out = make_flow_mod(OFPFC_ADD, flow, actions_len);
@@ -173,7 +173,7 @@ make_add_flow(const flow_t *flow, uint32_t buffer_id,
 }
 
 struct ofpbuf *
-make_del_flow(const flow_t *flow)
+make_del_flow(const struct flow *flow)
 {
     struct ofpbuf *out = make_flow_mod(OFPFC_DELETE_STRICT, flow, 0);
     struct ofp_flow_mod *ofm = out->data;
@@ -182,7 +182,7 @@ make_del_flow(const flow_t *flow)
 }
 
 struct ofpbuf *
-make_add_simple_flow(const flow_t *flow,
+make_add_simple_flow(const struct flow *flow,
                      uint32_t buffer_id, uint16_t out_port,
                      uint16_t idle_timeout)
 {
@@ -303,7 +303,7 @@ make_echo_reply(const struct ofp_header *rq)
 }
 
 static int
-check_message_type(uint8_t got_type, uint8_t want_type) 
+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);
@@ -564,6 +564,9 @@ check_nicira_action(const union ofp_action *a, unsigned int len)
     switch (ntohs(nah->subtype)) {
     case NXAST_RESUBMIT:
     case NXAST_SET_TUNNEL:
+    case NXAST_DROP_SPOOFED_ARP:
+    case NXAST_SET_QUEUE:
+    case NXAST_POP_QUEUE:
         return check_action_exact_len(a, len, 16);
     default:
         return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE);
@@ -584,7 +587,25 @@ check_action(const union ofp_action *a, unsigned int len, int max_ports)
         return check_output_port(ntohs(a->output.port), max_ports);
 
     case OFPAT_SET_VLAN_VID:
+        error = check_action_exact_len(a, len, 8);
+        if (error) {
+            return error;
+        }
+        if (a->vlan_vid.vlan_vid & ~htons(0xfff)) {
+            return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
+        }
+        return 0;
+
     case OFPAT_SET_VLAN_PCP:
+        error = check_action_exact_len(a, len, 8);
+        if (error) {
+            return error;
+        }
+        if (a->vlan_vid.vlan_vid & ~7) {
+            return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_ARGUMENT);
+        }
+        return 0;
+
     case OFPAT_STRIP_VLAN:
     case OFPAT_SET_NW_SRC:
     case OFPAT_SET_NW_DST:
@@ -616,9 +637,10 @@ int
 validate_actions(const union ofp_action *actions, size_t n_actions,
                  int max_ports)
 {
-    const union ofp_action *a;
+    size_t i;
 
-    for (a = actions; a < &actions[n_actions]; ) {
+    for (i = 0; i < n_actions; ) {
+        const union ofp_action *a = &actions[i];
         unsigned int len = ntohs(a->header.len);
         unsigned int n_slots = len / ACTION_ALIGNMENT;
         unsigned int slots_left = &actions[n_actions] - a;
@@ -642,7 +664,7 @@ validate_actions(const union ofp_action *actions, size_t n_actions,
         if (error) {
             return error;
         }
-        a += n_slots;
+        i += n_slots;
     }
     return 0;
 }
@@ -676,7 +698,7 @@ actions_first(struct actions_iterator *iter,
 const union ofp_action *
 actions_next(struct actions_iterator *iter)
 {
-    if (iter->pos < iter->end) {
+    if (iter->pos != iter->end) {
         const union ofp_action *a = iter->pos;
         unsigned int len = ntohs(a->header.len);
         iter->pos += len / ACTION_ALIGNMENT;