Commit fc37ddce authored by Chad Dupuis's avatar Chad Dupuis Committed by Martin K. Petersen
Browse files

scsi: qedf: Check both the FCF and fabric ID before servicing clear virtual link



 - Check proper values before servicing CVL.

Signed-off-by: default avatarChad Dupuis <cdupuis@marvell.com>
Signed-off-by: default avatarSaurav Kashyap <skashyap@marvell.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 56efc304
Loading
Loading
Loading
Loading
+48 −18
Original line number Diff line number Diff line
@@ -151,6 +151,8 @@ void qedf_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)
	qed_ops->ll2->start_xmit(qedf->cdev, skb, 0);
}

static u8 fcoe_all_enode[ETH_ALEN] = FIP_ALL_ENODE_MACS;

/* Process incoming FIP frames. */
void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb)
{
@@ -163,20 +165,37 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb)
	size_t rlen, dlen;
	u16 op;
	u8 sub;
	bool do_reset = false;
	bool fcf_valid = false;
	/* Default is to handle CVL regardless of fabric id descriptor */
	bool fabric_id_valid = true;
	bool fc_wwpn_valid = false;
	u64 switch_name;
	u16 vlan = 0;

	eth_hdr = (struct ethhdr *)skb_mac_header(skb);
	fiph = (struct fip_header *) ((void *)skb->data + 2 * ETH_ALEN + 2);
	op = ntohs(fiph->fip_op);
	sub = fiph->fip_subcode;

	QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, "FIP frame received: "
	    "skb=%p fiph=%p source=%pM op=%x sub=%x", skb, fiph,
	    eth_hdr->h_source, op, sub);
	QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2,
		  "FIP frame received: skb=%p fiph=%p source=%pM destn=%pM op=%x sub=%x vlan=%04x",
		  skb, fiph, eth_hdr->h_source, eth_hdr->h_dest, op,
		  sub, vlan);
	if (qedf_dump_frames)
		print_hex_dump(KERN_WARNING, "fip ", DUMP_PREFIX_OFFSET, 16, 1,
		    skb->data, skb->len, false);

	if (!ether_addr_equal(eth_hdr->h_dest, qedf->mac) &&
	    !ether_addr_equal(eth_hdr->h_dest, fcoe_all_enode) &&
		!ether_addr_equal(eth_hdr->h_dest, qedf->data_src_addr)) {
		QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_LL2,
			  "Dropping FIP type 0x%x pkt due to destination MAC mismatch dest_mac=%pM ctlr.dest_addr=%pM data_src_addr=%pM.\n",
			  op, eth_hdr->h_dest, qedf->mac,
			  qedf->data_src_addr);
		kfree_skb(skb);
		return;
	}

	/* Handle FIP VLAN resp in the driver */
	if (op == FIP_OP_VLAN && sub == FIP_SC_VL_NOTE) {
		qedf_fcoe_process_vlan_resp(qedf, skb);
@@ -205,25 +224,36 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb)
			switch (desc->fip_dtype) {
			case FIP_DT_MAC:
				mp = (struct fip_mac_desc *)desc;
				QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2,
				    "fd_mac=%pM\n", mp->fd_mac);
				QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
					  "Switch fd_mac=%pM.\n", mp->fd_mac);
				if (ether_addr_equal(mp->fd_mac,
				    qedf->ctlr.sel_fcf->fcf_mac))
					do_reset = true;
					fcf_valid = true;
				break;
			case FIP_DT_NAME:
				wp = (struct fip_wwn_desc *)desc;
				QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2,
				    "fc_wwpn=%016llx.\n",
				    get_unaligned_be64(&wp->fd_wwn));
				switch_name = get_unaligned_be64(&wp->fd_wwn);
				QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
					  "Switch fd_wwn=%016llx fcf_switch_name=%016llx.\n",
					  switch_name,
					  qedf->ctlr.sel_fcf->switch_name);
				if (switch_name ==
				    qedf->ctlr.sel_fcf->switch_name)
					fc_wwpn_valid = true;
				break;
			case FIP_DT_VN_ID:
				vp = (struct fip_vn_desc *)desc;
				QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2,
				    "fd_fc_id=%x.\n", ntoh24(vp->fd_fc_id));
				if (ntoh24(vp->fd_fc_id) ==
				QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
					  "vx_port fd_fc_id=%x fd_mac=%pM.\n",
					  ntoh24(vp->fd_fc_id), vp->fd_mac);
				/* Check vx_port fabric ID */
				if (ntoh24(vp->fd_fc_id) !=
				    qedf->lport->port_id)
					do_reset = true;
					fabric_id_valid = false;
				/* Check vx_port MAC */
				if (!ether_addr_equal(vp->fd_mac,
						      qedf->data_src_addr))
					fabric_id_valid = false;
				break;
			default:
				/* Ignore anything else */
@@ -233,11 +263,11 @@ void qedf_fip_recv(struct qedf_ctx *qedf, struct sk_buff *skb)
			rlen -= dlen;
		}

		QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2,
		    "do_reset=%d.\n", do_reset);
		if (do_reset) {
		QEDF_INFO(&qedf->dbg_ctx, QEDF_LOG_DISC,
			  "fcf_valid=%d fabric_id_valid=%d fc_wwpn_valid=%d.\n",
			  fcf_valid, fabric_id_valid, fc_wwpn_valid);
		if (fcf_valid && fabric_id_valid && fc_wwpn_valid)
			qedf_ctx_soft_reset(qedf->lport);
		}
		kfree_skb(skb);
	} else {
		/* Everything else is handled by libfcoe */