net/mlx4_core: Make sure that negative array index isn't used
[deliverable/linux.git] / drivers / net / ethernet / mellanox / mlx4 / mcg.c
index 80ccb4edf825f8888c6487626f2f380c7b27479b..04a8636a0b7e6d2cb8a4c8ba9d8ceb78a8b95a97 100644 (file)
@@ -363,8 +363,20 @@ static bool can_remove_steering_entry(struct mlx4_dev *dev, u8 port,
        ret = true;
        list_for_each_entry_safe(entry, tmp_entry, &s_steer->steer_entries[steer], list) {
                if (entry->index == index) {
-                       if (list_empty(&entry->duplicates)) {
+                       if (list_empty(&entry->duplicates) ||
+                           members_count == 1) {
+                               struct mlx4_promisc_qp *pqp, *tmp_pqp;
+                               /* If there is only 1 entry in duplicates then
+                                * this is the QP we want to delete, going over
+                                * the list and deleting the entry.
+                                */
                                list_del(&entry->list);
+                               list_for_each_entry_safe(pqp, tmp_pqp,
+                                                        &entry->duplicates,
+                                                        list) {
+                                       list_del(&pqp->list);
+                                       kfree(pqp);
+                               }
                                kfree(entry);
                        } else {
                                /* This entry contains duplicates so it shouldn't be removed */
@@ -501,7 +513,7 @@ static int remove_promisc_qp(struct mlx4_dev *dev, u8 port,
        u32 members_count;
        bool found;
        bool back_to_list = false;
-       int loc, i;
+       int i;
        int err;
 
        if (port < 1 || port > dev->caps.num_ports)
@@ -553,18 +565,30 @@ static int remove_promisc_qp(struct mlx4_dev *dev, u8 port,
                        list_del(&dqp->list);
                        kfree(dqp);
                } else {
+                       int loc = -1;
                        err = mlx4_READ_ENTRY(dev, entry->index, mailbox);
                                if (err)
                                        goto out_mailbox;
                        members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
-                       for (loc = -1, i = 0; i < members_count; ++i)
-                               if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qpn)
+                       for (i = 0; i < members_count; ++i)
+                               if ((be32_to_cpu(mgm->qp[i]) &
+                                    MGM_QPN_MASK) == qpn) {
                                        loc = i;
+                                       break;
+                               }
+
+                       if (loc < 0) {
+                               mlx4_err(dev, "QP %06x wasn't found in entry %d\n",
+                                        qpn, entry->index);
+                               err = -EINVAL;
+                               goto out_mailbox;
+                       }
 
+                       /* copy the last QP in this MGM over removed QP */
+                       mgm->qp[loc] = mgm->qp[members_count - 1];
+                       mgm->qp[members_count - 1] = 0;
                        mgm->members_count = cpu_to_be32(--members_count |
                                                         (MLX4_PROT_ETH << 30));
-                       mgm->qp[loc] = mgm->qp[i - 1];
-                       mgm->qp[i - 1] = 0;
 
                        err = mlx4_WRITE_ENTRY(dev, entry->index, mailbox);
                                if (err)
@@ -638,7 +662,7 @@ static int find_entry(struct mlx4_dev *dev, u8 port,
 
                if (!(be32_to_cpu(mgm->members_count) & 0xffffff)) {
                        if (*index != hash) {
-                               mlx4_err(dev, "Found zero MGID in AMGM.\n");
+                               mlx4_err(dev, "Found zero MGID in AMGM\n");
                                err = -EINVAL;
                        }
                        return err;
@@ -874,7 +898,7 @@ static void mlx4_err_rule(struct mlx4_dev *dev, char *str,
        mlx4_err(dev, "%s", buf);
 
        if (len >= BUF_SIZE)
-               mlx4_err(dev, "Network rule error message was truncated, print buffer is too small.\n");
+               mlx4_err(dev, "Network rule error message was truncated, print buffer is too small\n");
 }
 
 int mlx4_flow_attach(struct mlx4_dev *dev,
@@ -897,7 +921,7 @@ int mlx4_flow_attach(struct mlx4_dev *dev,
                ret = parse_trans_rule(dev, cur, mailbox->buf + size);
                if (ret < 0) {
                        mlx4_free_cmd_mailbox(dev, mailbox);
-                       return -EINVAL;
+                       return ret;
                }
                size += ret;
        }
@@ -905,10 +929,10 @@ int mlx4_flow_attach(struct mlx4_dev *dev,
        ret = mlx4_QP_FLOW_STEERING_ATTACH(dev, mailbox, size >> 2, reg_id);
        if (ret == -ENOMEM)
                mlx4_err_rule(dev,
-                             "mcg table is full. Fail to register network rule.\n",
+                             "mcg table is full. Fail to register network rule\n",
                              rule);
        else if (ret)
-               mlx4_err_rule(dev, "Fail to register network rule.\n", rule);
+               mlx4_err_rule(dev, "Fail to register network rule\n", rule);
 
        mlx4_free_cmd_mailbox(dev, mailbox);
 
@@ -994,7 +1018,7 @@ int mlx4_qp_attach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
 
        members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
        if (members_count == dev->caps.num_qp_per_mgm) {
-               mlx4_err(dev, "MGM at index %x is full.\n", index);
+               mlx4_err(dev, "MGM at index %x is full\n", index);
                err = -ENOMEM;
                goto out;
        }
@@ -1042,7 +1066,7 @@ out:
        }
        if (err && link && index != -1) {
                if (index < dev->caps.num_mgms)
-                       mlx4_warn(dev, "Got AMGM index %d < %d",
+                       mlx4_warn(dev, "Got AMGM index %d < %d\n",
                                  index, dev->caps.num_mgms);
                else
                        mlx4_bitmap_free(&priv->mcg_table.bitmap,
@@ -1062,7 +1086,7 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
        struct mlx4_mgm *mgm;
        u32 members_count;
        int prev, index;
-       int i, loc;
+       int i, loc = -1;
        int err;
        u8 port = gid[5];
        bool removed_entry = false;
@@ -1091,9 +1115,11 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
                goto out;
 
        members_count = be32_to_cpu(mgm->members_count) & 0xffffff;
-       for (loc = -1, i = 0; i < members_count; ++i)
-               if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn)
+       for (i = 0; i < members_count; ++i)
+               if ((be32_to_cpu(mgm->qp[i]) & MGM_QPN_MASK) == qp->qpn) {
                        loc = i;
+                       break;
+               }
 
        if (loc == -1) {
                mlx4_err(dev, "QP %06x not found in MGM\n", qp->qpn);
@@ -1101,15 +1127,15 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
                goto out;
        }
 
-
+       /* copy the last QP in this MGM over removed QP */
+       mgm->qp[loc] = mgm->qp[members_count - 1];
+       mgm->qp[members_count - 1] = 0;
        mgm->members_count = cpu_to_be32(--members_count | (u32) prot << 30);
-       mgm->qp[loc]       = mgm->qp[i - 1];
-       mgm->qp[i - 1]     = 0;
 
        if (prot == MLX4_PROT_ETH)
                removed_entry = can_remove_steering_entry(dev, port, steer,
                                                                index, qp->qpn);
-       if (i != 1 && (prot != MLX4_PROT_ETH || !removed_entry)) {
+       if (members_count && (prot != MLX4_PROT_ETH || !removed_entry)) {
                err = mlx4_WRITE_ENTRY(dev, index, mailbox);
                goto out;
        }
@@ -1133,7 +1159,7 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
 
                if (amgm_index) {
                        if (amgm_index < dev->caps.num_mgms)
-                               mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d",
+                               mlx4_warn(dev, "MGM entry %d had AMGM index %d < %d\n",
                                          index, amgm_index, dev->caps.num_mgms);
                        else
                                mlx4_bitmap_free(&priv->mcg_table.bitmap,
@@ -1153,7 +1179,7 @@ int mlx4_qp_detach_common(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16],
                        goto out;
 
                if (index < dev->caps.num_mgms)
-                       mlx4_warn(dev, "entry %d had next AMGM index %d < %d",
+                       mlx4_warn(dev, "entry %d had next AMGM index %d < %d\n",
                                  prev, index, dev->caps.num_mgms);
                else
                        mlx4_bitmap_free(&priv->mcg_table.bitmap,
This page took 0.032731 seconds and 5 git commands to generate.