aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/fcoe/libfcoe.c
diff options
context:
space:
mode:
authorBhanu Prakash Gollapudi <bprakash@broadcom.com>2010-06-11 19:44:25 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-07-27 13:01:49 -0400
commit0a9c5d344dbd983af59865f9880621e5cbbda899 (patch)
treeac07b32be5fbde24902bea64ab3ef8bd057b4de3 /drivers/scsi/fcoe/libfcoe.c
parentc600fea2d813e8734748202970722c3b6a76b9a1 (diff)
[SCSI] libfcoe: Handle duplicate critical descriptors
As per FC-BB-5 rev 2, section 7.8.6.2, malformed FIP frame shall be discarded. Drop discovery adv, ELS and CLV's with duplicate critical descriptors. [Resending after incorporating Joe's review comments] Signed-off-by: Bhanu Prakash Gollapudi <bprakash@broadcom.com> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/fcoe/libfcoe.c')
-rw-r--r--drivers/scsi/fcoe/libfcoe.c41
1 files changed, 41 insertions, 0 deletions
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
index 27c21ca802b2..db7185c0b964 100644
--- a/drivers/scsi/fcoe/libfcoe.c
+++ b/drivers/scsi/fcoe/libfcoe.c
@@ -640,6 +640,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
640 unsigned long t; 640 unsigned long t;
641 size_t rlen; 641 size_t rlen;
642 size_t dlen; 642 size_t dlen;
643 u32 desc_mask;
643 644
644 memset(fcf, 0, sizeof(*fcf)); 645 memset(fcf, 0, sizeof(*fcf));
645 fcf->fka_period = msecs_to_jiffies(FCOE_CTLR_DEF_FKA); 646 fcf->fka_period = msecs_to_jiffies(FCOE_CTLR_DEF_FKA);
@@ -647,6 +648,12 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
647 fiph = (struct fip_header *)skb->data; 648 fiph = (struct fip_header *)skb->data;
648 fcf->flags = ntohs(fiph->fip_flags); 649 fcf->flags = ntohs(fiph->fip_flags);
649 650
651 /*
652 * mask of required descriptors. validating each one clears its bit.
653 */
654 desc_mask = BIT(FIP_DT_PRI) | BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) |
655 BIT(FIP_DT_FAB) | BIT(FIP_DT_FKA);
656
650 rlen = ntohs(fiph->fip_dl_len) * 4; 657 rlen = ntohs(fiph->fip_dl_len) * 4;
651 if (rlen + sizeof(*fiph) > skb->len) 658 if (rlen + sizeof(*fiph) > skb->len)
652 return -EINVAL; 659 return -EINVAL;
@@ -656,11 +663,19 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
656 dlen = desc->fip_dlen * FIP_BPW; 663 dlen = desc->fip_dlen * FIP_BPW;
657 if (dlen < sizeof(*desc) || dlen > rlen) 664 if (dlen < sizeof(*desc) || dlen > rlen)
658 return -EINVAL; 665 return -EINVAL;
666 /* Drop Adv if there are duplicate critical descriptors */
667 if ((desc->fip_dtype < 32) &&
668 !(desc_mask & 1U << desc->fip_dtype)) {
669 LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
670 "Descriptors in FIP adv\n");
671 return -EINVAL;
672 }
659 switch (desc->fip_dtype) { 673 switch (desc->fip_dtype) {
660 case FIP_DT_PRI: 674 case FIP_DT_PRI:
661 if (dlen != sizeof(struct fip_pri_desc)) 675 if (dlen != sizeof(struct fip_pri_desc))
662 goto len_err; 676 goto len_err;
663 fcf->pri = ((struct fip_pri_desc *)desc)->fd_pri; 677 fcf->pri = ((struct fip_pri_desc *)desc)->fd_pri;
678 desc_mask &= ~BIT(FIP_DT_PRI);
664 break; 679 break;
665 case FIP_DT_MAC: 680 case FIP_DT_MAC:
666 if (dlen != sizeof(struct fip_mac_desc)) 681 if (dlen != sizeof(struct fip_mac_desc))
@@ -673,12 +688,14 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
673 "in FIP adv\n"); 688 "in FIP adv\n");
674 return -EINVAL; 689 return -EINVAL;
675 } 690 }
691 desc_mask &= ~BIT(FIP_DT_MAC);
676 break; 692 break;
677 case FIP_DT_NAME: 693 case FIP_DT_NAME:
678 if (dlen != sizeof(struct fip_wwn_desc)) 694 if (dlen != sizeof(struct fip_wwn_desc))
679 goto len_err; 695 goto len_err;
680 wwn = (struct fip_wwn_desc *)desc; 696 wwn = (struct fip_wwn_desc *)desc;
681 fcf->switch_name = get_unaligned_be64(&wwn->fd_wwn); 697 fcf->switch_name = get_unaligned_be64(&wwn->fd_wwn);
698 desc_mask &= ~BIT(FIP_DT_NAME);
682 break; 699 break;
683 case FIP_DT_FAB: 700 case FIP_DT_FAB:
684 if (dlen != sizeof(struct fip_fab_desc)) 701 if (dlen != sizeof(struct fip_fab_desc))
@@ -687,6 +704,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
687 fcf->fabric_name = get_unaligned_be64(&fab->fd_wwn); 704 fcf->fabric_name = get_unaligned_be64(&fab->fd_wwn);
688 fcf->vfid = ntohs(fab->fd_vfid); 705 fcf->vfid = ntohs(fab->fd_vfid);
689 fcf->fc_map = ntoh24(fab->fd_map); 706 fcf->fc_map = ntoh24(fab->fd_map);
707 desc_mask &= ~BIT(FIP_DT_FAB);
690 break; 708 break;
691 case FIP_DT_FKA: 709 case FIP_DT_FKA:
692 if (dlen != sizeof(struct fip_fka_desc)) 710 if (dlen != sizeof(struct fip_fka_desc))
@@ -697,6 +715,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
697 t = ntohl(fka->fd_fka_period); 715 t = ntohl(fka->fd_fka_period);
698 if (t >= FCOE_CTLR_MIN_FKA) 716 if (t >= FCOE_CTLR_MIN_FKA)
699 fcf->fka_period = msecs_to_jiffies(t); 717 fcf->fka_period = msecs_to_jiffies(t);
718 desc_mask &= ~BIT(FIP_DT_FKA);
700 break; 719 break;
701 case FIP_DT_MAP_OUI: 720 case FIP_DT_MAP_OUI:
702 case FIP_DT_FCOE_SIZE: 721 case FIP_DT_FCOE_SIZE:
@@ -719,6 +738,11 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
719 return -EINVAL; 738 return -EINVAL;
720 if (!fcf->switch_name || !fcf->fabric_name) 739 if (!fcf->switch_name || !fcf->fabric_name)
721 return -EINVAL; 740 return -EINVAL;
741 if (desc_mask) {
742 LIBFCOE_FIP_DBG(fip, "adv missing descriptors mask %x\n",
743 desc_mask);
744 return -EINVAL;
745 }
722 return 0; 746 return 0;
723 747
724len_err: 748len_err:
@@ -847,6 +871,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
847 size_t els_len = 0; 871 size_t els_len = 0;
848 size_t rlen; 872 size_t rlen;
849 size_t dlen; 873 size_t dlen;
874 u32 dupl_desc = 0;
850 875
851 fiph = (struct fip_header *)skb->data; 876 fiph = (struct fip_header *)skb->data;
852 sub = fiph->fip_subcode; 877 sub = fiph->fip_subcode;
@@ -862,6 +887,15 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
862 dlen = desc->fip_dlen * FIP_BPW; 887 dlen = desc->fip_dlen * FIP_BPW;
863 if (dlen < sizeof(*desc) || dlen > rlen) 888 if (dlen < sizeof(*desc) || dlen > rlen)
864 goto drop; 889 goto drop;
890 /* Drop ELS if there are duplicate critical descriptors */
891 if (desc->fip_dtype < 32) {
892 if (dupl_desc & 1U << desc->fip_dtype) {
893 LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
894 "Descriptors in FIP ELS\n");
895 goto drop;
896 }
897 dupl_desc |= (1 << desc->fip_dtype);
898 }
865 switch (desc->fip_dtype) { 899 switch (desc->fip_dtype) {
866 case FIP_DT_MAC: 900 case FIP_DT_MAC:
867 if (dlen != sizeof(struct fip_mac_desc)) 901 if (dlen != sizeof(struct fip_mac_desc))
@@ -973,6 +1007,13 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
973 dlen = desc->fip_dlen * FIP_BPW; 1007 dlen = desc->fip_dlen * FIP_BPW;
974 if (dlen > rlen) 1008 if (dlen > rlen)
975 return; 1009 return;
1010 /* Drop CVL if there are duplicate critical descriptors */
1011 if ((desc->fip_dtype < 32) &&
1012 !(desc_mask & 1U << desc->fip_dtype)) {
1013 LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
1014 "Descriptors in FIP CVL\n");
1015 return;
1016 }
976 switch (desc->fip_dtype) { 1017 switch (desc->fip_dtype) {
977 case FIP_DT_MAC: 1018 case FIP_DT_MAC:
978 mp = (struct fip_mac_desc *)desc; 1019 mp = (struct fip_mac_desc *)desc;