| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. |
|---|
| 3 | 4 | * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved. |
|---|
| 4 | | - * |
|---|
| 5 | | - * This software is available to you under a choice of one of two |
|---|
| 6 | | - * licenses. You may choose to be licensed under the terms of the GNU |
|---|
| 7 | | - * General Public License (GPL) Version 2, available from the file |
|---|
| 8 | | - * COPYING in the main directory of this source tree, or the |
|---|
| 9 | | - * OpenIB.org BSD license below: |
|---|
| 10 | | - * |
|---|
| 11 | | - * Redistribution and use in source and binary forms, with or |
|---|
| 12 | | - * without modification, are permitted provided that the following |
|---|
| 13 | | - * conditions are met: |
|---|
| 14 | | - * |
|---|
| 15 | | - * - Redistributions of source code must retain the above |
|---|
| 16 | | - * copyright notice, this list of conditions and the following |
|---|
| 17 | | - * disclaimer. |
|---|
| 18 | | - * |
|---|
| 19 | | - * - Redistributions in binary form must reproduce the above |
|---|
| 20 | | - * copyright notice, this list of conditions and the following |
|---|
| 21 | | - * disclaimer in the documentation and/or other materials |
|---|
| 22 | | - * provided with the distribution. |
|---|
| 23 | | - * |
|---|
| 24 | | - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
|---|
| 25 | | - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|---|
| 26 | | - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
|---|
| 27 | | - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS |
|---|
| 28 | | - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN |
|---|
| 29 | | - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
|---|
| 30 | | - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|---|
| 31 | | - * SOFTWARE. |
|---|
| 32 | 5 | */ |
|---|
| 33 | 6 | |
|---|
| 34 | 7 | #include <linux/skbuff.h> |
|---|
| .. | .. |
|---|
| 106 | 79 | static int check_keys(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, |
|---|
| 107 | 80 | u32 qpn, struct rxe_qp *qp) |
|---|
| 108 | 81 | { |
|---|
| 109 | | - int i; |
|---|
| 110 | | - int found_pkey = 0; |
|---|
| 111 | 82 | struct rxe_port *port = &rxe->port; |
|---|
| 112 | 83 | u16 pkey = bth_pkey(pkt); |
|---|
| 113 | 84 | |
|---|
| 114 | 85 | pkt->pkey_index = 0; |
|---|
| 115 | 86 | |
|---|
| 116 | | - if (qpn == 1) { |
|---|
| 117 | | - for (i = 0; i < port->attr.pkey_tbl_len; i++) { |
|---|
| 118 | | - if (pkey_match(pkey, port->pkey_tbl[i])) { |
|---|
| 119 | | - pkt->pkey_index = i; |
|---|
| 120 | | - found_pkey = 1; |
|---|
| 121 | | - break; |
|---|
| 122 | | - } |
|---|
| 123 | | - } |
|---|
| 124 | | - |
|---|
| 125 | | - if (!found_pkey) { |
|---|
| 126 | | - pr_warn_ratelimited("bad pkey = 0x%x\n", pkey); |
|---|
| 127 | | - set_bad_pkey_cntr(port); |
|---|
| 128 | | - goto err1; |
|---|
| 129 | | - } |
|---|
| 130 | | - } else if (qpn != 0) { |
|---|
| 131 | | - if (unlikely(!pkey_match(pkey, |
|---|
| 132 | | - port->pkey_tbl[qp->attr.pkey_index] |
|---|
| 133 | | - ))) { |
|---|
| 134 | | - pr_warn_ratelimited("bad pkey = 0x%0x\n", pkey); |
|---|
| 135 | | - set_bad_pkey_cntr(port); |
|---|
| 136 | | - goto err1; |
|---|
| 137 | | - } |
|---|
| 138 | | - pkt->pkey_index = qp->attr.pkey_index; |
|---|
| 87 | + if (!pkey_match(pkey, IB_DEFAULT_PKEY_FULL)) { |
|---|
| 88 | + pr_warn_ratelimited("bad pkey = 0x%x\n", pkey); |
|---|
| 89 | + set_bad_pkey_cntr(port); |
|---|
| 90 | + goto err1; |
|---|
| 139 | 91 | } |
|---|
| 140 | 92 | |
|---|
| 141 | 93 | if ((qp_type(qp) == IB_QPT_UD || qp_type(qp) == IB_QPT_GSI) && |
|---|
| 142 | | - qpn != 0 && pkt->mask) { |
|---|
| 94 | + pkt->mask) { |
|---|
| 143 | 95 | u32 qkey = (qpn == 1) ? GSI_QKEY : qp->attr.qkey; |
|---|
| 144 | 96 | |
|---|
| 145 | 97 | if (unlikely(deth_qkey(pkt) != qkey)) { |
|---|
| .. | .. |
|---|
| 271 | 223 | return -EINVAL; |
|---|
| 272 | 224 | } |
|---|
| 273 | 225 | |
|---|
| 274 | | -static inline void rxe_rcv_pkt(struct rxe_dev *rxe, |
|---|
| 275 | | - struct rxe_pkt_info *pkt, |
|---|
| 276 | | - struct sk_buff *skb) |
|---|
| 226 | +static inline void rxe_rcv_pkt(struct rxe_pkt_info *pkt, struct sk_buff *skb) |
|---|
| 277 | 227 | { |
|---|
| 278 | 228 | if (pkt->mask & RXE_REQ_MASK) |
|---|
| 279 | | - rxe_resp_queue_pkt(rxe, pkt->qp, skb); |
|---|
| 229 | + rxe_resp_queue_pkt(pkt->qp, skb); |
|---|
| 280 | 230 | else |
|---|
| 281 | | - rxe_comp_queue_pkt(rxe, pkt->qp, skb); |
|---|
| 231 | + rxe_comp_queue_pkt(pkt->qp, skb); |
|---|
| 282 | 232 | } |
|---|
| 283 | 233 | |
|---|
| 284 | 234 | static void rxe_rcv_mcast_pkt(struct rxe_dev *rxe, struct sk_buff *skb) |
|---|
| .. | .. |
|---|
| 288 | 238 | struct rxe_mc_elem *mce; |
|---|
| 289 | 239 | struct rxe_qp *qp; |
|---|
| 290 | 240 | union ib_gid dgid; |
|---|
| 241 | + struct sk_buff *per_qp_skb; |
|---|
| 242 | + struct rxe_pkt_info *per_qp_pkt; |
|---|
| 291 | 243 | int err; |
|---|
| 292 | 244 | |
|---|
| 293 | 245 | if (skb->protocol == htons(ETH_P_IP)) |
|---|
| .. | .. |
|---|
| 305 | 257 | |
|---|
| 306 | 258 | list_for_each_entry(mce, &mcg->qp_list, qp_list) { |
|---|
| 307 | 259 | qp = mce->qp; |
|---|
| 308 | | - pkt = SKB_TO_PKT(skb); |
|---|
| 309 | 260 | |
|---|
| 310 | 261 | /* validate qp for incoming packet */ |
|---|
| 311 | 262 | err = check_type_state(rxe, pkt, qp); |
|---|
| .. | .. |
|---|
| 316 | 267 | if (err) |
|---|
| 317 | 268 | continue; |
|---|
| 318 | 269 | |
|---|
| 319 | | - /* if *not* the last qp in the list |
|---|
| 320 | | - * increase the users of the skb then post to the next qp |
|---|
| 270 | + /* for all but the last qp create a new clone of the |
|---|
| 271 | + * skb and pass to the qp. If an error occurs in the |
|---|
| 272 | + * checks for the last qp in the list we need to |
|---|
| 273 | + * free the skb since it hasn't been passed on to |
|---|
| 274 | + * rxe_rcv_pkt() which would free it later. |
|---|
| 321 | 275 | */ |
|---|
| 322 | | - if (mce->qp_list.next != &mcg->qp_list) |
|---|
| 323 | | - skb_get(skb); |
|---|
| 276 | + if (mce->qp_list.next != &mcg->qp_list) { |
|---|
| 277 | + per_qp_skb = skb_clone(skb, GFP_ATOMIC); |
|---|
| 278 | + } else { |
|---|
| 279 | + per_qp_skb = skb; |
|---|
| 280 | + /* show we have consumed the skb */ |
|---|
| 281 | + skb = NULL; |
|---|
| 282 | + } |
|---|
| 324 | 283 | |
|---|
| 325 | | - pkt->qp = qp; |
|---|
| 284 | + if (unlikely(!per_qp_skb)) |
|---|
| 285 | + continue; |
|---|
| 286 | + |
|---|
| 287 | + per_qp_pkt = SKB_TO_PKT(per_qp_skb); |
|---|
| 288 | + per_qp_pkt->qp = qp; |
|---|
| 326 | 289 | rxe_add_ref(qp); |
|---|
| 327 | | - rxe_rcv_pkt(rxe, pkt, skb); |
|---|
| 290 | + rxe_rcv_pkt(per_qp_pkt, per_qp_skb); |
|---|
| 328 | 291 | } |
|---|
| 329 | 292 | |
|---|
| 330 | 293 | spin_unlock_bh(&mcg->mcg_lock); |
|---|
| .. | .. |
|---|
| 332 | 295 | rxe_drop_ref(mcg); /* drop ref from rxe_pool_get_key. */ |
|---|
| 333 | 296 | |
|---|
| 334 | 297 | err1: |
|---|
| 298 | + /* free skb if not consumed */ |
|---|
| 335 | 299 | kfree_skb(skb); |
|---|
| 336 | 300 | } |
|---|
| 337 | 301 | |
|---|
| 338 | | -static int rxe_match_dgid(struct rxe_dev *rxe, struct sk_buff *skb) |
|---|
| 302 | +/** |
|---|
| 303 | + * rxe_chk_dgid - validate destination IP address |
|---|
| 304 | + * @rxe: rxe device that received packet |
|---|
| 305 | + * @skb: the received packet buffer |
|---|
| 306 | + * |
|---|
| 307 | + * Accept any loopback packets |
|---|
| 308 | + * Extract IP address from packet and |
|---|
| 309 | + * Accept if multicast packet |
|---|
| 310 | + * Accept if matches an SGID table entry |
|---|
| 311 | + */ |
|---|
| 312 | +static int rxe_chk_dgid(struct rxe_dev *rxe, struct sk_buff *skb) |
|---|
| 339 | 313 | { |
|---|
| 340 | 314 | struct rxe_pkt_info *pkt = SKB_TO_PKT(skb); |
|---|
| 341 | 315 | const struct ib_gid_attr *gid_attr; |
|---|
| .. | .. |
|---|
| 352 | 326 | } else { |
|---|
| 353 | 327 | pdgid = (union ib_gid *)&ipv6_hdr(skb)->daddr; |
|---|
| 354 | 328 | } |
|---|
| 329 | + |
|---|
| 330 | + if (rdma_is_multicast_addr((struct in6_addr *)pdgid)) |
|---|
| 331 | + return 0; |
|---|
| 355 | 332 | |
|---|
| 356 | 333 | gid_attr = rdma_find_gid_by_port(&rxe->ib_dev, pdgid, |
|---|
| 357 | 334 | IB_GID_TYPE_ROCE_UDP_ENCAP, |
|---|
| .. | .. |
|---|
| 377 | 354 | if (unlikely(skb->len < pkt->offset + RXE_BTH_BYTES)) |
|---|
| 378 | 355 | goto drop; |
|---|
| 379 | 356 | |
|---|
| 380 | | - if (rxe_match_dgid(rxe, skb) < 0) { |
|---|
| 381 | | - pr_warn_ratelimited("failed matching dgid\n"); |
|---|
| 357 | + if (rxe_chk_dgid(rxe, skb) < 0) { |
|---|
| 358 | + pr_warn_ratelimited("failed checking dgid\n"); |
|---|
| 382 | 359 | goto drop; |
|---|
| 383 | 360 | } |
|---|
| 384 | 361 | |
|---|
| .. | .. |
|---|
| 420 | 397 | if (unlikely(bth_qpn(pkt) == IB_MULTICAST_QPN)) |
|---|
| 421 | 398 | rxe_rcv_mcast_pkt(rxe, skb); |
|---|
| 422 | 399 | else |
|---|
| 423 | | - rxe_rcv_pkt(rxe, pkt, skb); |
|---|
| 400 | + rxe_rcv_pkt(pkt, skb); |
|---|
| 424 | 401 | |
|---|
| 425 | 402 | return; |
|---|
| 426 | 403 | |
|---|