}
}
+static char const cm_drop_reason_desc[4][32] = {
+ "N/A",
+ "No GRH",
+ "grh.guid != mad.guid",
+ "acl drop"
+};
+
+enum cm_drop_reason {
+ CM_DROP_ACCEPT,
+ CM_DROP_NO_GRH,
+ CM_DROP_INV_MAD_GUID,
+ CM_DROP_ACL
+};
+
+static enum cm_drop_reason cm_acl_filter(struct cm_work *work)
+{
+ struct cm_req_msg *req_msg;
+ struct ib_grh *grh;
+ struct ib_cm_dpp dpp;
+ struct ib_cm_acl *acl;
+ u64 subnet_prefix = 0, guid = 0;
+ struct ib_wc *wc;
+ enum cm_drop_reason drop = CM_DROP_ACCEPT;
+
+ req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad;
+ grh = (struct ib_grh *)work->mad_recv_wc->recv_buf.grh;
+ wc = (struct ib_wc *)work->mad_recv_wc->wc;
+
+ ib_cm_dpp_init(&dpp, work->port->cm_dev->ib_device,
+ work->port->port_num, be16_to_cpu(req_msg->pkey));
+ ib_cm_dpp_dbg("CM Request from interface", &dpp);
+ acl = ib_cm_dpp_acl_lookup(&dpp);
+ if (acl && acl->enabled) {
+ if (!(wc->wc_flags & IB_WC_GRH))
+ drop = CM_DROP_NO_GRH;
+ else if (grh->sgid.global.interface_id !=
+ req_msg->primary_local_gid.global.interface_id)
+ drop = CM_DROP_INV_MAD_GUID;
+ else {
+ subnet_prefix = be64_to_cpu(req_msg->
+ primary_local_gid.global.
+ subnet_prefix);
+ guid = be64_to_cpu(req_msg->primary_local_gid.global.
+ interface_id);
+ if (!ib_cm_acl_lookup(acl, subnet_prefix, guid))
+ drop = CM_DROP_ACL;
+ }
+
+ if (drop) {
+ pr_debug("Blocked CM request, reason=%s\n",
+ cm_drop_reason_desc[drop]);
+ pr_debug("\tgrh.sgid=(0x%llx,0x%llx), grh.dgid=(0x%llx,0x%llx)\n",
+ be64_to_cpu(grh->sgid.global.subnet_prefix),
+ be64_to_cpu(grh->sgid.global.interface_id),
+ be64_to_cpu(grh->dgid.global.subnet_prefix),
+ be64_to_cpu(grh->dgid.global.interface_id));
+ pr_debug("\tlocal=(0x%llx,0x%llx), remote=(0x%llx,0x%llx)\n",
+ be64_to_cpu(req_msg->primary_local_gid.global.
+ subnet_prefix),
+ be64_to_cpu(req_msg->primary_local_gid.global.
+ interface_id),
+ be64_to_cpu(req_msg->primary_remote_gid.global.
+ subnet_prefix),
+ be64_to_cpu(req_msg->primary_remote_gid.global.
+ interface_id));
+ }
+ }
+
+ return drop;
+}
+
static int cm_req_handler(struct cm_work *work)
{
struct ib_cm_id *cm_id;
struct cm_id_private *cm_id_priv, *listen_cm_id_priv;
struct cm_req_msg *req_msg;
- int ret;
+ int ret = 0;
+
+ ret = cm_acl_filter(work);
+ if (ret)
+ return -EINVAL;
req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad;
#include <linux/ip.h>
#include <linux/tcp.h>
+#include <net/arp.h>
#include "ipoib.h"
return 0;
}
+static inline int ipoib_is_valid_arp_address(struct net_device *dev,
+ struct sk_buff *skb,
+ __be64 interface_id)
+{
+ struct ipoib_dev_priv *priv = netdev_priv(dev);
+ union ib_gid *sgid;
+
+ sgid = (union ib_gid *)(skb->data + sizeof(struct arphdr) + 4);
+
+ if (sgid->global.interface_id != interface_id) {
+ ipoib_dbg(priv, "Invalid ARP: sguid=0x%llx, arp.sguid=0x%llx\n",
+ be64_to_cpu(interface_id),
+ be64_to_cpu(sgid->global.interface_id));
+ return 0;
+ }
+
+ return 1;
+}
+
+static char const ipoib_drop_reason_desc[5][32] = {
+ "N/A",
+ "No GRH",
+ "grh.guid != arp.guid",
+ "acl",
+ "non CM packet"
+};
+
+enum ipoib_drop_reason {
+ IPOIB_DROP_ACCEPT,
+ IPOIB_DROP_NO_GRH,
+ IPOIB_DROP_INV_ARP_GUID,
+ IPOIB_DROP_ACL,
+ IPOIB_DROP_NON_CM_PACKRT
+};
+
static void ipoib_ib_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
unsigned int wr_id = wc->wr_id & ~IPOIB_OP_RECV;
struct sk_buff *skb;
u64 mapping[IPOIB_UD_RX_SG];
- union ib_gid *dgid;
+ union ib_gid *dgid, *sgid;
+ enum ipoib_drop_reason drop = IPOIB_DROP_ACCEPT;
+ u64 subnet_prefix = 0, guid = 0;
ipoib_dbg_data(priv, "recv completion: id %d, status: %d\n",
wr_id, wc->status);
return;
}
- skb = priv->rx_ring[wr_id].skb;
+ skb = priv->rx_ring[wr_id].skb;
if (unlikely(wc->status != IB_WC_SUCCESS)) {
if (wc->status != IB_WC_WR_FLUSH_ERR)
/* First byte of dgid signals multicast when 0xff */
dgid = &((struct ib_grh *)skb->data)->dgid;
+ sgid = &((struct ib_grh *)skb->data)->sgid;
if (!(wc->wc_flags & IB_WC_GRH) || dgid->raw[0] != 0xff)
skb->pkt_type = PACKET_HOST;
++dev->stats.rx_packets;
dev->stats.rx_bytes += skb->len;
+ if (unlikely(be16_to_cpu(skb->protocol) == ETH_P_ARP)) {
+ if (priv->acl.enabled) {
+ subnet_prefix = be64_to_cpu(sgid->global.subnet_prefix);
+ guid = be64_to_cpu(sgid->global.interface_id);
+ if (!(wc->wc_flags & IB_WC_GRH))
+ drop = IPOIB_DROP_NO_GRH;
+ else if (!ipoib_is_valid_arp_address(dev, skb,
+ sgid->global.interface_id))
+ drop = IPOIB_DROP_INV_ARP_GUID;
+ else if (!ib_cm_acl_lookup(&priv->acl, subnet_prefix,
+ guid))
+ drop = IPOIB_DROP_ACL;
+ if (drop) {
+ goto drop;
+ priv->arp_blocked++;
+ }
+ }
+ priv->arp_accepted++;
+ } else
+ if (priv->acl.enabled) {
+ priv->ud_blocked++;
+ drop = IPOIB_DROP_NON_CM_PACKRT;
+ goto drop;
+ }
+
skb->dev = dev;
if ((dev->features & NETIF_F_RXCSUM) &&
likely(wc->wc_flags & IB_WC_IP_CSUM_OK))
napi_gro_receive(&priv->napi, skb);
+ goto repost;
+
+drop:
+ ipoib_dbg(priv, "Blocking packet (%s) from 0x%llx 0x%llx\n",
+ ipoib_drop_reason_desc[drop], subnet_prefix, guid);
+ dev_kfree_skb_any(skb);
+ ++dev->stats.rx_dropped;
+ goto repost;
+
repost:
if (unlikely(ipoib_ib_post_receive(dev, wr_id)))
ipoib_warn(priv, "ipoib_ib_post_receive failed "