net/mlx4_core: Make sure that negative array index isn't used
[deliverable/linux.git] / drivers / net / ethernet / mellanox / mlx4 / mcg.c
index 4c36def8e10f9b518a1ba8a3f05340eb63c4dc0a..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)
@@ -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;
        }
This page took 0.042526 seconds and 5 git commands to generate.