diff options
author | Bhanu Prakash Gollapudi <bprakash@broadcom.com> | 2010-06-11 19:44:25 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-07-27 13:01:49 -0400 |
commit | 0a9c5d344dbd983af59865f9880621e5cbbda899 (patch) | |
tree | ac07b32be5fbde24902bea64ab3ef8bd057b4de3 /drivers/scsi/fcoe/libfcoe.c | |
parent | c600fea2d813e8734748202970722c3b6a76b9a1 (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.c | 41 |
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 | ||
724 | len_err: | 748 | len_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; |