diff options
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 37 |
1 files changed, 35 insertions, 2 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 0a5ad95ac8b0..32f7a3b3d43c 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -572,24 +572,40 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
572 | size_t left = len; | 572 | size_t left = len; |
573 | u8 *pos = start; | 573 | u8 *pos = start; |
574 | bool calc_crc = filter != 0; | 574 | bool calc_crc = filter != 0; |
575 | DECLARE_BITMAP(seen_elems, 256); | ||
575 | 576 | ||
577 | bitmap_zero(seen_elems, 256); | ||
576 | memset(elems, 0, sizeof(*elems)); | 578 | memset(elems, 0, sizeof(*elems)); |
577 | elems->ie_start = start; | 579 | elems->ie_start = start; |
578 | elems->total_len = len; | 580 | elems->total_len = len; |
579 | 581 | ||
580 | while (left >= 2) { | 582 | while (left >= 2) { |
581 | u8 id, elen; | 583 | u8 id, elen; |
584 | bool elem_parse_failed; | ||
582 | 585 | ||
583 | id = *pos++; | 586 | id = *pos++; |
584 | elen = *pos++; | 587 | elen = *pos++; |
585 | left -= 2; | 588 | left -= 2; |
586 | 589 | ||
587 | if (elen > left) | 590 | if (elen > left) { |
591 | elems->parse_error = true; | ||
588 | break; | 592 | break; |
593 | } | ||
594 | |||
595 | if (id != WLAN_EID_VENDOR_SPECIFIC && | ||
596 | id != WLAN_EID_QUIET && | ||
597 | test_bit(id, seen_elems)) { | ||
598 | elems->parse_error = true; | ||
599 | left -= elen; | ||
600 | pos += elen; | ||
601 | continue; | ||
602 | } | ||
589 | 603 | ||
590 | if (calc_crc && id < 64 && (filter & (1ULL << id))) | 604 | if (calc_crc && id < 64 && (filter & (1ULL << id))) |
591 | crc = crc32_be(crc, pos - 2, elen + 2); | 605 | crc = crc32_be(crc, pos - 2, elen + 2); |
592 | 606 | ||
607 | elem_parse_failed = false; | ||
608 | |||
593 | switch (id) { | 609 | switch (id) { |
594 | case WLAN_EID_SSID: | 610 | case WLAN_EID_SSID: |
595 | elems->ssid = pos; | 611 | elems->ssid = pos; |
@@ -615,7 +631,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
615 | if (elen >= sizeof(struct ieee80211_tim_ie)) { | 631 | if (elen >= sizeof(struct ieee80211_tim_ie)) { |
616 | elems->tim = (void *)pos; | 632 | elems->tim = (void *)pos; |
617 | elems->tim_len = elen; | 633 | elems->tim_len = elen; |
618 | } | 634 | } else |
635 | elem_parse_failed = true; | ||
619 | break; | 636 | break; |
620 | case WLAN_EID_IBSS_PARAMS: | 637 | case WLAN_EID_IBSS_PARAMS: |
621 | elems->ibss_params = pos; | 638 | elems->ibss_params = pos; |
@@ -664,10 +681,14 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
664 | case WLAN_EID_HT_CAPABILITY: | 681 | case WLAN_EID_HT_CAPABILITY: |
665 | if (elen >= sizeof(struct ieee80211_ht_cap)) | 682 | if (elen >= sizeof(struct ieee80211_ht_cap)) |
666 | elems->ht_cap_elem = (void *)pos; | 683 | elems->ht_cap_elem = (void *)pos; |
684 | else | ||
685 | elem_parse_failed = true; | ||
667 | break; | 686 | break; |
668 | case WLAN_EID_HT_INFORMATION: | 687 | case WLAN_EID_HT_INFORMATION: |
669 | if (elen >= sizeof(struct ieee80211_ht_info)) | 688 | if (elen >= sizeof(struct ieee80211_ht_info)) |
670 | elems->ht_info_elem = (void *)pos; | 689 | elems->ht_info_elem = (void *)pos; |
690 | else | ||
691 | elem_parse_failed = true; | ||
671 | break; | 692 | break; |
672 | case WLAN_EID_MESH_ID: | 693 | case WLAN_EID_MESH_ID: |
673 | elems->mesh_id = pos; | 694 | elems->mesh_id = pos; |
@@ -676,6 +697,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
676 | case WLAN_EID_MESH_CONFIG: | 697 | case WLAN_EID_MESH_CONFIG: |
677 | if (elen >= sizeof(struct ieee80211_meshconf_ie)) | 698 | if (elen >= sizeof(struct ieee80211_meshconf_ie)) |
678 | elems->mesh_config = (void *)pos; | 699 | elems->mesh_config = (void *)pos; |
700 | else | ||
701 | elem_parse_failed = true; | ||
679 | break; | 702 | break; |
680 | case WLAN_EID_PEER_MGMT: | 703 | case WLAN_EID_PEER_MGMT: |
681 | elems->peering = pos; | 704 | elems->peering = pos; |
@@ -696,6 +719,8 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
696 | case WLAN_EID_RANN: | 719 | case WLAN_EID_RANN: |
697 | if (elen >= sizeof(struct ieee80211_rann_ie)) | 720 | if (elen >= sizeof(struct ieee80211_rann_ie)) |
698 | elems->rann = (void *)pos; | 721 | elems->rann = (void *)pos; |
722 | else | ||
723 | elem_parse_failed = true; | ||
699 | break; | 724 | break; |
700 | case WLAN_EID_CHANNEL_SWITCH: | 725 | case WLAN_EID_CHANNEL_SWITCH: |
701 | elems->ch_switch_elem = pos; | 726 | elems->ch_switch_elem = pos; |
@@ -724,10 +749,18 @@ u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | |||
724 | break; | 749 | break; |
725 | } | 750 | } |
726 | 751 | ||
752 | if (elem_parse_failed) | ||
753 | elems->parse_error = true; | ||
754 | else | ||
755 | set_bit(id, seen_elems); | ||
756 | |||
727 | left -= elen; | 757 | left -= elen; |
728 | pos += elen; | 758 | pos += elen; |
729 | } | 759 | } |
730 | 760 | ||
761 | if (left != 0) | ||
762 | elems->parse_error = true; | ||
763 | |||
731 | return crc; | 764 | return crc; |
732 | } | 765 | } |
733 | 766 | ||