Bluetooth: Set the link for SCO connection
[platform/kernel/linux-rpi.git] / net / openvswitch / datapath.c
index 67ad083..795a25e 100644 (file)
@@ -251,10 +251,17 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key)
 
                upcall.mru = OVS_CB(skb)->mru;
                error = ovs_dp_upcall(dp, skb, key, &upcall, 0);
-               if (unlikely(error))
-                       kfree_skb(skb);
-               else
+               switch (error) {
+               case 0:
+               case -EAGAIN:
+               case -ERESTARTSYS:
+               case -EINTR:
                        consume_skb(skb);
+                       break;
+               default:
+                       kfree_skb(skb);
+                       break;
+               }
                stats_counter = &stats->n_missed;
                goto out;
        }
@@ -550,8 +557,9 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
 out:
        if (err)
                skb_tx_error(skb);
-       kfree_skb(user_skb);
-       kfree_skb(nskb);
+       consume_skb(user_skb);
+       consume_skb(nskb);
+
        return err;
 }
 
@@ -938,6 +946,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
        struct sw_flow_mask mask;
        struct sk_buff *reply;
        struct datapath *dp;
+       struct sw_flow_key *key;
        struct sw_flow_actions *acts;
        struct sw_flow_match match;
        u32 ufid_flags = ovs_nla_get_ufid_flags(a[OVS_FLOW_ATTR_UFID_FLAGS]);
@@ -965,24 +974,26 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
        }
 
        /* Extract key. */
-       ovs_match_init(&match, &new_flow->key, false, &mask);
+       key = kzalloc(sizeof(*key), GFP_KERNEL);
+       if (!key) {
+               error = -ENOMEM;
+               goto err_kfree_key;
+       }
+
+       ovs_match_init(&match, key, false, &mask);
        error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY],
                                  a[OVS_FLOW_ATTR_MASK], log);
        if (error)
                goto err_kfree_flow;
 
+       ovs_flow_mask_key(&new_flow->key, key, true, &mask);
+
        /* Extract flow identifier. */
        error = ovs_nla_get_identifier(&new_flow->id, a[OVS_FLOW_ATTR_UFID],
-                                      &new_flow->key, log);
+                                      key, log);
        if (error)
                goto err_kfree_flow;
 
-       /* unmasked key is needed to match when ufid is not used. */
-       if (ovs_identifier_is_key(&new_flow->id))
-               match.key = new_flow->id.unmasked_key;
-
-       ovs_flow_mask_key(&new_flow->key, &new_flow->key, true, &mask);
-
        /* Validate actions. */
        error = ovs_nla_copy_actions(net, a[OVS_FLOW_ATTR_ACTIONS],
                                     &new_flow->key, &acts, log);
@@ -1009,7 +1020,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
        if (ovs_identifier_is_ufid(&new_flow->id))
                flow = ovs_flow_tbl_lookup_ufid(&dp->table, &new_flow->id);
        if (!flow)
-               flow = ovs_flow_tbl_lookup(&dp->table, &new_flow->key);
+               flow = ovs_flow_tbl_lookup(&dp->table, key);
        if (likely(!flow)) {
                rcu_assign_pointer(new_flow->sf_acts, acts);
 
@@ -1079,6 +1090,8 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info)
 
        if (reply)
                ovs_notify(&dp_flow_genl_family, reply, info);
+
+       kfree(key);
        return 0;
 
 err_unlock_ovs:
@@ -1088,6 +1101,8 @@ err_kfree_acts:
        ovs_nla_free_flow_actions(acts);
 err_kfree_flow:
        ovs_flow_free(new_flow, false);
+err_kfree_key:
+       kfree(key);
 error:
        return error;
 }
@@ -1597,7 +1612,8 @@ static void ovs_dp_reset_user_features(struct sk_buff *skb,
        if (IS_ERR(dp))
                return;
 
-       WARN(dp->user_features, "Dropping previously announced user features\n");
+       pr_warn("%s: Dropping previously announced user features\n",
+               ovs_dp_name(dp));
        dp->user_features = 0;
 }
 
@@ -1801,7 +1817,7 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
                                ovs_dp_reset_user_features(skb, info);
                }
 
-               goto err_unlock_and_destroy_meters;
+               goto err_destroy_portids;
        }
 
        err = ovs_dp_cmd_fill_info(dp, reply, info->snd_portid,
@@ -1816,6 +1832,8 @@ static int ovs_dp_cmd_new(struct sk_buff *skb, struct genl_info *info)
        ovs_notify(&dp_datapath_genl_family, reply, info);
        return 0;
 
+err_destroy_portids:
+       kfree(rcu_dereference_raw(dp->upcall_portids));
 err_unlock_and_destroy_meters:
        ovs_unlock();
        ovs_meters_exit(dp);