diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2008-06-30 05:23:09 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-06-30 17:37:40 -0400 |
commit | 1781a07fbe9cce3dc1697288a5edd260ea7edc02 (patch) | |
tree | be06e824b69af8d43edfeab2c78a353f0bf7f8ce /drivers/net/wireless/iwlwifi/iwl-rx.c | |
parent | 37deb2a0baf1bb540b723cc8a3972b42ff2daac6 (diff) |
iwlwifi: move RX handlers to iwl-rx.c
This patch moves RX handlers to iwl-rx.c
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Tomas Winkler <tomas.winkler@intel.com>
Signed-off-by: Zhu Yi <yi.zhu@intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-rx.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-rx.c | 853 |
1 files changed, 853 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index b3ca1375c01a..e0d3e2dd1d82 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c | |||
@@ -27,6 +27,7 @@ | |||
27 | * | 27 | * |
28 | *****************************************************************************/ | 28 | *****************************************************************************/ |
29 | 29 | ||
30 | #include <linux/etherdevice.h> | ||
30 | #include <net/mac80211.h> | 31 | #include <net/mac80211.h> |
31 | #include "iwl-eeprom.h" | 32 | #include "iwl-eeprom.h" |
32 | #include "iwl-dev.h" | 33 | #include "iwl-dev.h" |
@@ -541,3 +542,855 @@ void iwl_rx_statistics(struct iwl_priv *priv, | |||
541 | priv->cfg->ops->lib->temperature(priv, &pkt->u.stats); | 542 | priv->cfg->ops->lib->temperature(priv, &pkt->u.stats); |
542 | } | 543 | } |
543 | EXPORT_SYMBOL(iwl_rx_statistics); | 544 | EXPORT_SYMBOL(iwl_rx_statistics); |
545 | |||
546 | #define PERFECT_RSSI (-20) /* dBm */ | ||
547 | #define WORST_RSSI (-95) /* dBm */ | ||
548 | #define RSSI_RANGE (PERFECT_RSSI - WORST_RSSI) | ||
549 | |||
550 | /* Calculate an indication of rx signal quality (a percentage, not dBm!). | ||
551 | * See http://www.ces.clemson.edu/linux/signal_quality.shtml for info | ||
552 | * about formulas used below. */ | ||
553 | static int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm) | ||
554 | { | ||
555 | int sig_qual; | ||
556 | int degradation = PERFECT_RSSI - rssi_dbm; | ||
557 | |||
558 | /* If we get a noise measurement, use signal-to-noise ratio (SNR) | ||
559 | * as indicator; formula is (signal dbm - noise dbm). | ||
560 | * SNR at or above 40 is a great signal (100%). | ||
561 | * Below that, scale to fit SNR of 0 - 40 dB within 0 - 100% indicator. | ||
562 | * Weakest usable signal is usually 10 - 15 dB SNR. */ | ||
563 | if (noise_dbm) { | ||
564 | if (rssi_dbm - noise_dbm >= 40) | ||
565 | return 100; | ||
566 | else if (rssi_dbm < noise_dbm) | ||
567 | return 0; | ||
568 | sig_qual = ((rssi_dbm - noise_dbm) * 5) / 2; | ||
569 | |||
570 | /* Else use just the signal level. | ||
571 | * This formula is a least squares fit of data points collected and | ||
572 | * compared with a reference system that had a percentage (%) display | ||
573 | * for signal quality. */ | ||
574 | } else | ||
575 | sig_qual = (100 * (RSSI_RANGE * RSSI_RANGE) - degradation * | ||
576 | (15 * RSSI_RANGE + 62 * degradation)) / | ||
577 | (RSSI_RANGE * RSSI_RANGE); | ||
578 | |||
579 | if (sig_qual > 100) | ||
580 | sig_qual = 100; | ||
581 | else if (sig_qual < 1) | ||
582 | sig_qual = 0; | ||
583 | |||
584 | return sig_qual; | ||
585 | } | ||
586 | |||
587 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
588 | |||
589 | /** | ||
590 | * iwl_dbg_report_frame - dump frame to syslog during debug sessions | ||
591 | * | ||
592 | * You may hack this function to show different aspects of received frames, | ||
593 | * including selective frame dumps. | ||
594 | * group100 parameter selects whether to show 1 out of 100 good frames. | ||
595 | * | ||
596 | * TODO: This was originally written for 3945, need to audit for | ||
597 | * proper operation with 4965. | ||
598 | */ | ||
599 | static void iwl_dbg_report_frame(struct iwl_priv *priv, | ||
600 | struct iwl_rx_packet *pkt, | ||
601 | struct ieee80211_hdr *header, int group100) | ||
602 | { | ||
603 | u32 to_us; | ||
604 | u32 print_summary = 0; | ||
605 | u32 print_dump = 0; /* set to 1 to dump all frames' contents */ | ||
606 | u32 hundred = 0; | ||
607 | u32 dataframe = 0; | ||
608 | __le16 fc; | ||
609 | u16 seq_ctl; | ||
610 | u16 channel; | ||
611 | u16 phy_flags; | ||
612 | int rate_sym; | ||
613 | u16 length; | ||
614 | u16 status; | ||
615 | u16 bcn_tmr; | ||
616 | u32 tsf_low; | ||
617 | u64 tsf; | ||
618 | u8 rssi; | ||
619 | u8 agc; | ||
620 | u16 sig_avg; | ||
621 | u16 noise_diff; | ||
622 | struct iwl4965_rx_frame_stats *rx_stats = IWL_RX_STATS(pkt); | ||
623 | struct iwl4965_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt); | ||
624 | struct iwl4965_rx_frame_end *rx_end = IWL_RX_END(pkt); | ||
625 | u8 *data = IWL_RX_DATA(pkt); | ||
626 | |||
627 | if (likely(!(priv->debug_level & IWL_DL_RX))) | ||
628 | return; | ||
629 | |||
630 | /* MAC header */ | ||
631 | fc = header->frame_control; | ||
632 | seq_ctl = le16_to_cpu(header->seq_ctrl); | ||
633 | |||
634 | /* metadata */ | ||
635 | channel = le16_to_cpu(rx_hdr->channel); | ||
636 | phy_flags = le16_to_cpu(rx_hdr->phy_flags); | ||
637 | rate_sym = rx_hdr->rate; | ||
638 | length = le16_to_cpu(rx_hdr->len); | ||
639 | |||
640 | /* end-of-frame status and timestamp */ | ||
641 | status = le32_to_cpu(rx_end->status); | ||
642 | bcn_tmr = le32_to_cpu(rx_end->beacon_timestamp); | ||
643 | tsf_low = le64_to_cpu(rx_end->timestamp) & 0x0ffffffff; | ||
644 | tsf = le64_to_cpu(rx_end->timestamp); | ||
645 | |||
646 | /* signal statistics */ | ||
647 | rssi = rx_stats->rssi; | ||
648 | agc = rx_stats->agc; | ||
649 | sig_avg = le16_to_cpu(rx_stats->sig_avg); | ||
650 | noise_diff = le16_to_cpu(rx_stats->noise_diff); | ||
651 | |||
652 | to_us = !compare_ether_addr(header->addr1, priv->mac_addr); | ||
653 | |||
654 | /* if data frame is to us and all is good, | ||
655 | * (optionally) print summary for only 1 out of every 100 */ | ||
656 | if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) == | ||
657 | cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { | ||
658 | dataframe = 1; | ||
659 | if (!group100) | ||
660 | print_summary = 1; /* print each frame */ | ||
661 | else if (priv->framecnt_to_us < 100) { | ||
662 | priv->framecnt_to_us++; | ||
663 | print_summary = 0; | ||
664 | } else { | ||
665 | priv->framecnt_to_us = 0; | ||
666 | print_summary = 1; | ||
667 | hundred = 1; | ||
668 | } | ||
669 | } else { | ||
670 | /* print summary for all other frames */ | ||
671 | print_summary = 1; | ||
672 | } | ||
673 | |||
674 | if (print_summary) { | ||
675 | char *title; | ||
676 | int rate_idx; | ||
677 | u32 bitrate; | ||
678 | |||
679 | if (hundred) | ||
680 | title = "100Frames"; | ||
681 | else if (ieee80211_has_retry(fc)) | ||
682 | title = "Retry"; | ||
683 | else if (ieee80211_is_assoc_resp(fc)) | ||
684 | title = "AscRsp"; | ||
685 | else if (ieee80211_is_reassoc_resp(fc)) | ||
686 | title = "RasRsp"; | ||
687 | else if (ieee80211_is_probe_resp(fc)) { | ||
688 | title = "PrbRsp"; | ||
689 | print_dump = 1; /* dump frame contents */ | ||
690 | } else if (ieee80211_is_beacon(fc)) { | ||
691 | title = "Beacon"; | ||
692 | print_dump = 1; /* dump frame contents */ | ||
693 | } else if (ieee80211_is_atim(fc)) | ||
694 | title = "ATIM"; | ||
695 | else if (ieee80211_is_auth(fc)) | ||
696 | title = "Auth"; | ||
697 | else if (ieee80211_is_deauth(fc)) | ||
698 | title = "DeAuth"; | ||
699 | else if (ieee80211_is_disassoc(fc)) | ||
700 | title = "DisAssoc"; | ||
701 | else | ||
702 | title = "Frame"; | ||
703 | |||
704 | rate_idx = iwl_hwrate_to_plcp_idx(rate_sym); | ||
705 | if (unlikely(rate_idx == -1)) | ||
706 | bitrate = 0; | ||
707 | else | ||
708 | bitrate = iwl_rates[rate_idx].ieee / 2; | ||
709 | |||
710 | /* print frame summary. | ||
711 | * MAC addresses show just the last byte (for brevity), | ||
712 | * but you can hack it to show more, if you'd like to. */ | ||
713 | if (dataframe) | ||
714 | IWL_DEBUG_RX("%s: mhd=0x%04x, dst=0x%02x, " | ||
715 | "len=%u, rssi=%d, chnl=%d, rate=%u, \n", | ||
716 | title, le16_to_cpu(fc), header->addr1[5], | ||
717 | length, rssi, channel, bitrate); | ||
718 | else { | ||
719 | /* src/dst addresses assume managed mode */ | ||
720 | IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, " | ||
721 | "src=0x%02x, rssi=%u, tim=%lu usec, " | ||
722 | "phy=0x%02x, chnl=%d\n", | ||
723 | title, le16_to_cpu(fc), header->addr1[5], | ||
724 | header->addr3[5], rssi, | ||
725 | tsf_low - priv->scan_start_tsf, | ||
726 | phy_flags, channel); | ||
727 | } | ||
728 | } | ||
729 | if (print_dump) | ||
730 | iwl_print_hex_dump(priv, IWL_DL_RX, data, length); | ||
731 | } | ||
732 | #else | ||
733 | static inline void iwl_dbg_report_frame(struct iwl_priv *priv, | ||
734 | struct iwl_rx_packet *pkt, | ||
735 | struct ieee80211_hdr *header, | ||
736 | int group100) | ||
737 | { | ||
738 | } | ||
739 | #endif | ||
740 | |||
741 | static void iwl_add_radiotap(struct iwl_priv *priv, | ||
742 | struct sk_buff *skb, | ||
743 | struct iwl4965_rx_phy_res *rx_start, | ||
744 | struct ieee80211_rx_status *stats, | ||
745 | u32 ampdu_status) | ||
746 | { | ||
747 | s8 signal = stats->signal; | ||
748 | s8 noise = 0; | ||
749 | int rate = stats->rate_idx; | ||
750 | u64 tsf = stats->mactime; | ||
751 | __le16 antenna; | ||
752 | __le16 phy_flags_hw = rx_start->phy_flags; | ||
753 | struct iwl4965_rt_rx_hdr { | ||
754 | struct ieee80211_radiotap_header rt_hdr; | ||
755 | __le64 rt_tsf; /* TSF */ | ||
756 | u8 rt_flags; /* radiotap packet flags */ | ||
757 | u8 rt_rate; /* rate in 500kb/s */ | ||
758 | __le16 rt_channelMHz; /* channel in MHz */ | ||
759 | __le16 rt_chbitmask; /* channel bitfield */ | ||
760 | s8 rt_dbmsignal; /* signal in dBm, kluged to signed */ | ||
761 | s8 rt_dbmnoise; | ||
762 | u8 rt_antenna; /* antenna number */ | ||
763 | } __attribute__ ((packed)) *iwl4965_rt; | ||
764 | |||
765 | /* TODO: We won't have enough headroom for HT frames. Fix it later. */ | ||
766 | if (skb_headroom(skb) < sizeof(*iwl4965_rt)) { | ||
767 | if (net_ratelimit()) | ||
768 | printk(KERN_ERR "not enough headroom [%d] for " | ||
769 | "radiotap head [%zd]\n", | ||
770 | skb_headroom(skb), sizeof(*iwl4965_rt)); | ||
771 | return; | ||
772 | } | ||
773 | |||
774 | /* put radiotap header in front of 802.11 header and data */ | ||
775 | iwl4965_rt = (void *)skb_push(skb, sizeof(*iwl4965_rt)); | ||
776 | |||
777 | /* initialise radiotap header */ | ||
778 | iwl4965_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; | ||
779 | iwl4965_rt->rt_hdr.it_pad = 0; | ||
780 | |||
781 | /* total header + data */ | ||
782 | put_unaligned(cpu_to_le16(sizeof(*iwl4965_rt)), | ||
783 | &iwl4965_rt->rt_hdr.it_len); | ||
784 | |||
785 | /* Indicate all the fields we add to the radiotap header */ | ||
786 | put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) | | ||
787 | (1 << IEEE80211_RADIOTAP_FLAGS) | | ||
788 | (1 << IEEE80211_RADIOTAP_RATE) | | ||
789 | (1 << IEEE80211_RADIOTAP_CHANNEL) | | ||
790 | (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) | | ||
791 | (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) | | ||
792 | (1 << IEEE80211_RADIOTAP_ANTENNA)), | ||
793 | &iwl4965_rt->rt_hdr.it_present); | ||
794 | |||
795 | /* Zero the flags, we'll add to them as we go */ | ||
796 | iwl4965_rt->rt_flags = 0; | ||
797 | |||
798 | put_unaligned(cpu_to_le64(tsf), &iwl4965_rt->rt_tsf); | ||
799 | |||
800 | iwl4965_rt->rt_dbmsignal = signal; | ||
801 | iwl4965_rt->rt_dbmnoise = noise; | ||
802 | |||
803 | /* Convert the channel frequency and set the flags */ | ||
804 | put_unaligned(cpu_to_le16(stats->freq), &iwl4965_rt->rt_channelMHz); | ||
805 | if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK)) | ||
806 | put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | | ||
807 | IEEE80211_CHAN_5GHZ), | ||
808 | &iwl4965_rt->rt_chbitmask); | ||
809 | else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK) | ||
810 | put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK | | ||
811 | IEEE80211_CHAN_2GHZ), | ||
812 | &iwl4965_rt->rt_chbitmask); | ||
813 | else /* 802.11g */ | ||
814 | put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM | | ||
815 | IEEE80211_CHAN_2GHZ), | ||
816 | &iwl4965_rt->rt_chbitmask); | ||
817 | |||
818 | if (rate == -1) | ||
819 | iwl4965_rt->rt_rate = 0; | ||
820 | else | ||
821 | iwl4965_rt->rt_rate = iwl_rates[rate].ieee; | ||
822 | |||
823 | /* | ||
824 | * "antenna number" | ||
825 | * | ||
826 | * It seems that the antenna field in the phy flags value | ||
827 | * is actually a bitfield. This is undefined by radiotap, | ||
828 | * it wants an actual antenna number but I always get "7" | ||
829 | * for most legacy frames I receive indicating that the | ||
830 | * same frame was received on all three RX chains. | ||
831 | * | ||
832 | * I think this field should be removed in favour of a | ||
833 | * new 802.11n radiotap field "RX chains" that is defined | ||
834 | * as a bitmask. | ||
835 | */ | ||
836 | antenna = phy_flags_hw & RX_RES_PHY_FLAGS_ANTENNA_MSK; | ||
837 | iwl4965_rt->rt_antenna = le16_to_cpu(antenna) >> 4; | ||
838 | |||
839 | /* set the preamble flag if appropriate */ | ||
840 | if (phy_flags_hw & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) | ||
841 | iwl4965_rt->rt_flags |= IEEE80211_RADIOTAP_F_SHORTPRE; | ||
842 | |||
843 | stats->flag |= RX_FLAG_RADIOTAP; | ||
844 | } | ||
845 | |||
846 | static void iwl_update_rx_stats(struct iwl_priv *priv, u16 fc, u16 len) | ||
847 | { | ||
848 | /* 0 - mgmt, 1 - cnt, 2 - data */ | ||
849 | int idx = (fc & IEEE80211_FCTL_FTYPE) >> 2; | ||
850 | priv->rx_stats[idx].cnt++; | ||
851 | priv->rx_stats[idx].bytes += len; | ||
852 | } | ||
853 | |||
854 | /* | ||
855 | * returns non-zero if packet should be dropped | ||
856 | */ | ||
857 | static int iwl_set_decrypted_flag(struct iwl_priv *priv, | ||
858 | struct ieee80211_hdr *hdr, | ||
859 | u32 decrypt_res, | ||
860 | struct ieee80211_rx_status *stats) | ||
861 | { | ||
862 | u16 fc = le16_to_cpu(hdr->frame_control); | ||
863 | |||
864 | if (priv->active_rxon.filter_flags & RXON_FILTER_DIS_DECRYPT_MSK) | ||
865 | return 0; | ||
866 | |||
867 | if (!(fc & IEEE80211_FCTL_PROTECTED)) | ||
868 | return 0; | ||
869 | |||
870 | IWL_DEBUG_RX("decrypt_res:0x%x\n", decrypt_res); | ||
871 | switch (decrypt_res & RX_RES_STATUS_SEC_TYPE_MSK) { | ||
872 | case RX_RES_STATUS_SEC_TYPE_TKIP: | ||
873 | /* The uCode has got a bad phase 1 Key, pushes the packet. | ||
874 | * Decryption will be done in SW. */ | ||
875 | if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == | ||
876 | RX_RES_STATUS_BAD_KEY_TTAK) | ||
877 | break; | ||
878 | |||
879 | case RX_RES_STATUS_SEC_TYPE_WEP: | ||
880 | if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == | ||
881 | RX_RES_STATUS_BAD_ICV_MIC) { | ||
882 | /* bad ICV, the packet is destroyed since the | ||
883 | * decryption is inplace, drop it */ | ||
884 | IWL_DEBUG_RX("Packet destroyed\n"); | ||
885 | return -1; | ||
886 | } | ||
887 | case RX_RES_STATUS_SEC_TYPE_CCMP: | ||
888 | if ((decrypt_res & RX_RES_STATUS_DECRYPT_TYPE_MSK) == | ||
889 | RX_RES_STATUS_DECRYPT_OK) { | ||
890 | IWL_DEBUG_RX("hw decrypt successfully!!!\n"); | ||
891 | stats->flag |= RX_FLAG_DECRYPTED; | ||
892 | } | ||
893 | break; | ||
894 | |||
895 | default: | ||
896 | break; | ||
897 | } | ||
898 | return 0; | ||
899 | } | ||
900 | |||
901 | static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) | ||
902 | { | ||
903 | u32 decrypt_out = 0; | ||
904 | |||
905 | if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) == | ||
906 | RX_RES_STATUS_STATION_FOUND) | ||
907 | decrypt_out |= (RX_RES_STATUS_STATION_FOUND | | ||
908 | RX_RES_STATUS_NO_STATION_INFO_MISMATCH); | ||
909 | |||
910 | decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK); | ||
911 | |||
912 | /* packet was not encrypted */ | ||
913 | if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == | ||
914 | RX_RES_STATUS_SEC_TYPE_NONE) | ||
915 | return decrypt_out; | ||
916 | |||
917 | /* packet was encrypted with unknown alg */ | ||
918 | if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == | ||
919 | RX_RES_STATUS_SEC_TYPE_ERR) | ||
920 | return decrypt_out; | ||
921 | |||
922 | /* decryption was not done in HW */ | ||
923 | if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) != | ||
924 | RX_MPDU_RES_STATUS_DEC_DONE_MSK) | ||
925 | return decrypt_out; | ||
926 | |||
927 | switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) { | ||
928 | |||
929 | case RX_RES_STATUS_SEC_TYPE_CCMP: | ||
930 | /* alg is CCM: check MIC only */ | ||
931 | if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK)) | ||
932 | /* Bad MIC */ | ||
933 | decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; | ||
934 | else | ||
935 | decrypt_out |= RX_RES_STATUS_DECRYPT_OK; | ||
936 | |||
937 | break; | ||
938 | |||
939 | case RX_RES_STATUS_SEC_TYPE_TKIP: | ||
940 | if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) { | ||
941 | /* Bad TTAK */ | ||
942 | decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; | ||
943 | break; | ||
944 | } | ||
945 | /* fall through if TTAK OK */ | ||
946 | default: | ||
947 | if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) | ||
948 | decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; | ||
949 | else | ||
950 | decrypt_out |= RX_RES_STATUS_DECRYPT_OK; | ||
951 | break; | ||
952 | }; | ||
953 | |||
954 | IWL_DEBUG_RX("decrypt_in:0x%x decrypt_out = 0x%x\n", | ||
955 | decrypt_in, decrypt_out); | ||
956 | |||
957 | return decrypt_out; | ||
958 | } | ||
959 | |||
960 | static void iwl_handle_data_packet(struct iwl_priv *priv, int is_data, | ||
961 | int include_phy, | ||
962 | struct iwl_rx_mem_buffer *rxb, | ||
963 | struct ieee80211_rx_status *stats) | ||
964 | { | ||
965 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | ||
966 | struct iwl4965_rx_phy_res *rx_start = (include_phy) ? | ||
967 | (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : NULL; | ||
968 | struct ieee80211_hdr *hdr; | ||
969 | u16 len; | ||
970 | __le32 *rx_end; | ||
971 | unsigned int skblen; | ||
972 | u32 ampdu_status; | ||
973 | u32 ampdu_status_legacy; | ||
974 | |||
975 | if (!include_phy && priv->last_phy_res[0]) | ||
976 | rx_start = (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; | ||
977 | |||
978 | if (!rx_start) { | ||
979 | IWL_ERROR("MPDU frame without a PHY data\n"); | ||
980 | return; | ||
981 | } | ||
982 | if (include_phy) { | ||
983 | hdr = (struct ieee80211_hdr *)((u8 *) &rx_start[1] + | ||
984 | rx_start->cfg_phy_cnt); | ||
985 | |||
986 | len = le16_to_cpu(rx_start->byte_count); | ||
987 | |||
988 | rx_end = (__le32 *) ((u8 *) &pkt->u.raw[0] + | ||
989 | sizeof(struct iwl4965_rx_phy_res) + | ||
990 | rx_start->cfg_phy_cnt + len); | ||
991 | |||
992 | } else { | ||
993 | struct iwl4965_rx_mpdu_res_start *amsdu = | ||
994 | (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; | ||
995 | |||
996 | hdr = (struct ieee80211_hdr *)(pkt->u.raw + | ||
997 | sizeof(struct iwl4965_rx_mpdu_res_start)); | ||
998 | len = le16_to_cpu(amsdu->byte_count); | ||
999 | rx_start->byte_count = amsdu->byte_count; | ||
1000 | rx_end = (__le32 *) (((u8 *) hdr) + len); | ||
1001 | } | ||
1002 | /* In monitor mode allow 802.11 ACk frames (10 bytes) */ | ||
1003 | if (len > priv->hw_params.max_pkt_size || | ||
1004 | len < ((priv->iw_mode == IEEE80211_IF_TYPE_MNTR) ? 10 : 16)) { | ||
1005 | IWL_WARNING("byte count out of range [16,4K] : %d\n", len); | ||
1006 | return; | ||
1007 | } | ||
1008 | |||
1009 | ampdu_status = le32_to_cpu(*rx_end); | ||
1010 | skblen = ((u8 *) rx_end - (u8 *) &pkt->u.raw[0]) + sizeof(u32); | ||
1011 | |||
1012 | if (!include_phy) { | ||
1013 | /* New status scheme, need to translate */ | ||
1014 | ampdu_status_legacy = ampdu_status; | ||
1015 | ampdu_status = iwl_translate_rx_status(priv, ampdu_status); | ||
1016 | } | ||
1017 | |||
1018 | /* start from MAC */ | ||
1019 | skb_reserve(rxb->skb, (void *)hdr - (void *)pkt); | ||
1020 | skb_put(rxb->skb, len); /* end where data ends */ | ||
1021 | |||
1022 | /* We only process data packets if the interface is open */ | ||
1023 | if (unlikely(!priv->is_open)) { | ||
1024 | IWL_DEBUG_DROP_LIMIT | ||
1025 | ("Dropping packet while interface is not open.\n"); | ||
1026 | return; | ||
1027 | } | ||
1028 | |||
1029 | stats->flag = 0; | ||
1030 | hdr = (struct ieee80211_hdr *)rxb->skb->data; | ||
1031 | |||
1032 | /* in case of HW accelerated crypto and bad decryption, drop */ | ||
1033 | if (!priv->hw_params.sw_crypto && | ||
1034 | iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) | ||
1035 | return; | ||
1036 | |||
1037 | if (priv->add_radiotap) | ||
1038 | iwl_add_radiotap(priv, rxb->skb, rx_start, stats, ampdu_status); | ||
1039 | |||
1040 | iwl_update_rx_stats(priv, le16_to_cpu(hdr->frame_control), len); | ||
1041 | ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); | ||
1042 | priv->alloc_rxb_skb--; | ||
1043 | rxb->skb = NULL; | ||
1044 | } | ||
1045 | |||
1046 | /* Calc max signal level (dBm) among 3 possible receivers */ | ||
1047 | static int iwl_calc_rssi(struct iwl_priv *priv, | ||
1048 | struct iwl4965_rx_phy_res *rx_resp) | ||
1049 | { | ||
1050 | /* data from PHY/DSP regarding signal strength, etc., | ||
1051 | * contents are always there, not configurable by host. */ | ||
1052 | struct iwl4965_rx_non_cfg_phy *ncphy = | ||
1053 | (struct iwl4965_rx_non_cfg_phy *)rx_resp->non_cfg_phy; | ||
1054 | u32 agc = (le16_to_cpu(ncphy->agc_info) & IWL_AGC_DB_MASK) | ||
1055 | >> IWL_AGC_DB_POS; | ||
1056 | |||
1057 | u32 valid_antennae = | ||
1058 | (le16_to_cpu(rx_resp->phy_flags) & RX_PHY_FLAGS_ANTENNAE_MASK) | ||
1059 | >> RX_PHY_FLAGS_ANTENNAE_OFFSET; | ||
1060 | u8 max_rssi = 0; | ||
1061 | u32 i; | ||
1062 | |||
1063 | /* Find max rssi among 3 possible receivers. | ||
1064 | * These values are measured by the digital signal processor (DSP). | ||
1065 | * They should stay fairly constant even as the signal strength varies, | ||
1066 | * if the radio's automatic gain control (AGC) is working right. | ||
1067 | * AGC value (see below) will provide the "interesting" info. */ | ||
1068 | for (i = 0; i < 3; i++) | ||
1069 | if (valid_antennae & (1 << i)) | ||
1070 | max_rssi = max(ncphy->rssi_info[i << 1], max_rssi); | ||
1071 | |||
1072 | IWL_DEBUG_STATS("Rssi In A %d B %d C %d Max %d AGC dB %d\n", | ||
1073 | ncphy->rssi_info[0], ncphy->rssi_info[2], ncphy->rssi_info[4], | ||
1074 | max_rssi, agc); | ||
1075 | |||
1076 | /* dBm = max_rssi dB - agc dB - constant. | ||
1077 | * Higher AGC (higher radio gain) means lower signal. */ | ||
1078 | return max_rssi - agc - IWL_RSSI_OFFSET; | ||
1079 | } | ||
1080 | |||
1081 | static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) | ||
1082 | { | ||
1083 | unsigned long flags; | ||
1084 | |||
1085 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
1086 | priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; | ||
1087 | priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; | ||
1088 | priv->stations[sta_id].sta.sta.modify_mask = 0; | ||
1089 | priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; | ||
1090 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
1091 | |||
1092 | iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); | ||
1093 | } | ||
1094 | |||
1095 | static void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) | ||
1096 | { | ||
1097 | /* FIXME: need locking over ps_status ??? */ | ||
1098 | u8 sta_id = iwl_find_station(priv, addr); | ||
1099 | |||
1100 | if (sta_id != IWL_INVALID_STATION) { | ||
1101 | u8 sta_awake = priv->stations[sta_id]. | ||
1102 | ps_status == STA_PS_STATUS_WAKE; | ||
1103 | |||
1104 | if (sta_awake && ps_bit) | ||
1105 | priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; | ||
1106 | else if (!sta_awake && !ps_bit) { | ||
1107 | iwl_sta_modify_ps_wake(priv, sta_id); | ||
1108 | priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; | ||
1109 | } | ||
1110 | } | ||
1111 | } | ||
1112 | |||
1113 | #define IWL_PACKET_RETRY_TIME HZ | ||
1114 | |||
1115 | static int iwl_is_duplicate_packet(struct iwl_priv *priv, | ||
1116 | struct ieee80211_hdr *header) | ||
1117 | { | ||
1118 | u16 sc = le16_to_cpu(header->seq_ctrl); | ||
1119 | u16 seq = (sc & IEEE80211_SCTL_SEQ) >> 4; | ||
1120 | u16 frag = sc & IEEE80211_SCTL_FRAG; | ||
1121 | u16 *last_seq, *last_frag; | ||
1122 | unsigned long *last_time; | ||
1123 | |||
1124 | switch (priv->iw_mode) { | ||
1125 | case IEEE80211_IF_TYPE_IBSS:{ | ||
1126 | struct list_head *p; | ||
1127 | struct iwl4965_ibss_seq *entry = NULL; | ||
1128 | u8 *mac = header->addr2; | ||
1129 | int index = mac[5] & (IWL_IBSS_MAC_HASH_SIZE - 1); | ||
1130 | |||
1131 | __list_for_each(p, &priv->ibss_mac_hash[index]) { | ||
1132 | entry = list_entry(p, struct iwl4965_ibss_seq, list); | ||
1133 | if (!compare_ether_addr(entry->mac, mac)) | ||
1134 | break; | ||
1135 | } | ||
1136 | if (p == &priv->ibss_mac_hash[index]) { | ||
1137 | entry = kzalloc(sizeof(*entry), GFP_ATOMIC); | ||
1138 | if (!entry) { | ||
1139 | IWL_ERROR("Cannot malloc new mac entry\n"); | ||
1140 | return 0; | ||
1141 | } | ||
1142 | memcpy(entry->mac, mac, ETH_ALEN); | ||
1143 | entry->seq_num = seq; | ||
1144 | entry->frag_num = frag; | ||
1145 | entry->packet_time = jiffies; | ||
1146 | list_add(&entry->list, &priv->ibss_mac_hash[index]); | ||
1147 | return 0; | ||
1148 | } | ||
1149 | last_seq = &entry->seq_num; | ||
1150 | last_frag = &entry->frag_num; | ||
1151 | last_time = &entry->packet_time; | ||
1152 | break; | ||
1153 | } | ||
1154 | case IEEE80211_IF_TYPE_STA: | ||
1155 | last_seq = &priv->last_seq_num; | ||
1156 | last_frag = &priv->last_frag_num; | ||
1157 | last_time = &priv->last_packet_time; | ||
1158 | break; | ||
1159 | default: | ||
1160 | return 0; | ||
1161 | } | ||
1162 | if ((*last_seq == seq) && | ||
1163 | time_after(*last_time + IWL_PACKET_RETRY_TIME, jiffies)) { | ||
1164 | if (*last_frag == frag) | ||
1165 | goto drop; | ||
1166 | if (*last_frag + 1 != frag) | ||
1167 | /* out-of-order fragment */ | ||
1168 | goto drop; | ||
1169 | } else | ||
1170 | *last_seq = seq; | ||
1171 | |||
1172 | *last_frag = frag; | ||
1173 | *last_time = jiffies; | ||
1174 | return 0; | ||
1175 | |||
1176 | drop: | ||
1177 | return 1; | ||
1178 | } | ||
1179 | |||
1180 | static int iwl_is_network_packet(struct iwl_priv *priv, | ||
1181 | struct ieee80211_hdr *header) | ||
1182 | { | ||
1183 | /* Filter incoming packets to determine if they are targeted toward | ||
1184 | * this network, discarding packets coming from ourselves */ | ||
1185 | switch (priv->iw_mode) { | ||
1186 | case IEEE80211_IF_TYPE_IBSS: /* Header: Dest. | Source | BSSID */ | ||
1187 | /* packets from our adapter are dropped (echo) */ | ||
1188 | if (!compare_ether_addr(header->addr2, priv->mac_addr)) | ||
1189 | return 0; | ||
1190 | /* {broad,multi}cast packets to our IBSS go through */ | ||
1191 | if (is_multicast_ether_addr(header->addr1)) | ||
1192 | return !compare_ether_addr(header->addr3, priv->bssid); | ||
1193 | /* packets to our adapter go through */ | ||
1194 | return !compare_ether_addr(header->addr1, priv->mac_addr); | ||
1195 | case IEEE80211_IF_TYPE_STA: /* Header: Dest. | AP{BSSID} | Source */ | ||
1196 | /* packets from our adapter are dropped (echo) */ | ||
1197 | if (!compare_ether_addr(header->addr3, priv->mac_addr)) | ||
1198 | return 0; | ||
1199 | /* {broad,multi}cast packets to our BSS go through */ | ||
1200 | if (is_multicast_ether_addr(header->addr1)) | ||
1201 | return !compare_ether_addr(header->addr2, priv->bssid); | ||
1202 | /* packets to our adapter go through */ | ||
1203 | return !compare_ether_addr(header->addr1, priv->mac_addr); | ||
1204 | default: | ||
1205 | break; | ||
1206 | } | ||
1207 | |||
1208 | return 1; | ||
1209 | } | ||
1210 | |||
1211 | /* Called for REPLY_RX (legacy ABG frames), or | ||
1212 | * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ | ||
1213 | void iwl_rx_reply_rx(struct iwl_priv *priv, | ||
1214 | struct iwl_rx_mem_buffer *rxb) | ||
1215 | { | ||
1216 | struct ieee80211_hdr *header; | ||
1217 | struct ieee80211_rx_status rx_status; | ||
1218 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | ||
1219 | /* Use phy data (Rx signal strength, etc.) contained within | ||
1220 | * this rx packet for legacy frames, | ||
1221 | * or phy data cached from REPLY_RX_PHY_CMD for HT frames. */ | ||
1222 | int include_phy = (pkt->hdr.cmd == REPLY_RX); | ||
1223 | struct iwl4965_rx_phy_res *rx_start = (include_phy) ? | ||
1224 | (struct iwl4965_rx_phy_res *)&(pkt->u.raw[0]) : | ||
1225 | (struct iwl4965_rx_phy_res *)&priv->last_phy_res[1]; | ||
1226 | __le32 *rx_end; | ||
1227 | unsigned int len = 0; | ||
1228 | u16 fc; | ||
1229 | u8 network_packet; | ||
1230 | |||
1231 | rx_status.mactime = le64_to_cpu(rx_start->timestamp); | ||
1232 | rx_status.freq = | ||
1233 | ieee80211_channel_to_frequency(le16_to_cpu(rx_start->channel)); | ||
1234 | rx_status.band = (rx_start->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? | ||
1235 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; | ||
1236 | rx_status.rate_idx = | ||
1237 | iwl_hwrate_to_plcp_idx(le32_to_cpu(rx_start->rate_n_flags)); | ||
1238 | if (rx_status.band == IEEE80211_BAND_5GHZ) | ||
1239 | rx_status.rate_idx -= IWL_FIRST_OFDM_RATE; | ||
1240 | |||
1241 | rx_status.antenna = 0; | ||
1242 | rx_status.flag = 0; | ||
1243 | |||
1244 | if ((unlikely(rx_start->cfg_phy_cnt > 20))) { | ||
1245 | IWL_DEBUG_DROP("dsp size out of range [0,20]: %d/n", | ||
1246 | rx_start->cfg_phy_cnt); | ||
1247 | return; | ||
1248 | } | ||
1249 | |||
1250 | if (!include_phy) { | ||
1251 | if (priv->last_phy_res[0]) | ||
1252 | rx_start = (struct iwl4965_rx_phy_res *) | ||
1253 | &priv->last_phy_res[1]; | ||
1254 | else | ||
1255 | rx_start = NULL; | ||
1256 | } | ||
1257 | |||
1258 | if (!rx_start) { | ||
1259 | IWL_ERROR("MPDU frame without a PHY data\n"); | ||
1260 | return; | ||
1261 | } | ||
1262 | |||
1263 | if (include_phy) { | ||
1264 | header = (struct ieee80211_hdr *)((u8 *) &rx_start[1] | ||
1265 | + rx_start->cfg_phy_cnt); | ||
1266 | |||
1267 | len = le16_to_cpu(rx_start->byte_count); | ||
1268 | rx_end = (__le32 *)(pkt->u.raw + rx_start->cfg_phy_cnt + | ||
1269 | sizeof(struct iwl4965_rx_phy_res) + len); | ||
1270 | } else { | ||
1271 | struct iwl4965_rx_mpdu_res_start *amsdu = | ||
1272 | (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; | ||
1273 | |||
1274 | header = (void *)(pkt->u.raw + | ||
1275 | sizeof(struct iwl4965_rx_mpdu_res_start)); | ||
1276 | len = le16_to_cpu(amsdu->byte_count); | ||
1277 | rx_end = (__le32 *) (pkt->u.raw + | ||
1278 | sizeof(struct iwl4965_rx_mpdu_res_start) + len); | ||
1279 | } | ||
1280 | |||
1281 | if (!(*rx_end & RX_RES_STATUS_NO_CRC32_ERROR) || | ||
1282 | !(*rx_end & RX_RES_STATUS_NO_RXE_OVERFLOW)) { | ||
1283 | IWL_DEBUG_RX("Bad CRC or FIFO: 0x%08X.\n", | ||
1284 | le32_to_cpu(*rx_end)); | ||
1285 | return; | ||
1286 | } | ||
1287 | |||
1288 | priv->ucode_beacon_time = le32_to_cpu(rx_start->beacon_time_stamp); | ||
1289 | |||
1290 | /* Find max signal strength (dBm) among 3 antenna/receiver chains */ | ||
1291 | rx_status.signal = iwl_calc_rssi(priv, rx_start); | ||
1292 | |||
1293 | /* Meaningful noise values are available only from beacon statistics, | ||
1294 | * which are gathered only when associated, and indicate noise | ||
1295 | * only for the associated network channel ... | ||
1296 | * Ignore these noise values while scanning (other channels) */ | ||
1297 | if (iwl_is_associated(priv) && | ||
1298 | !test_bit(STATUS_SCANNING, &priv->status)) { | ||
1299 | rx_status.noise = priv->last_rx_noise; | ||
1300 | rx_status.qual = iwl_calc_sig_qual(rx_status.signal, | ||
1301 | rx_status.noise); | ||
1302 | } else { | ||
1303 | rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | ||
1304 | rx_status.qual = iwl_calc_sig_qual(rx_status.signal, 0); | ||
1305 | } | ||
1306 | |||
1307 | /* Reset beacon noise level if not associated. */ | ||
1308 | if (!iwl_is_associated(priv)) | ||
1309 | priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | ||
1310 | |||
1311 | /* Set "1" to report good data frames in groups of 100 */ | ||
1312 | /* FIXME: need to optimze the call: */ | ||
1313 | iwl_dbg_report_frame(priv, pkt, header, 1); | ||
1314 | |||
1315 | IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", | ||
1316 | rx_status.signal, rx_status.noise, rx_status.signal, | ||
1317 | (unsigned long long)rx_status.mactime); | ||
1318 | |||
1319 | |||
1320 | if (priv->iw_mode == IEEE80211_IF_TYPE_MNTR) { | ||
1321 | iwl_handle_data_packet(priv, 1, include_phy, | ||
1322 | rxb, &rx_status); | ||
1323 | return; | ||
1324 | } | ||
1325 | |||
1326 | network_packet = iwl_is_network_packet(priv, header); | ||
1327 | if (network_packet) { | ||
1328 | priv->last_rx_rssi = rx_status.signal; | ||
1329 | priv->last_beacon_time = priv->ucode_beacon_time; | ||
1330 | priv->last_tsf = le64_to_cpu(rx_start->timestamp); | ||
1331 | } | ||
1332 | |||
1333 | fc = le16_to_cpu(header->frame_control); | ||
1334 | switch (fc & IEEE80211_FCTL_FTYPE) { | ||
1335 | case IEEE80211_FTYPE_MGMT: | ||
1336 | if (priv->iw_mode == IEEE80211_IF_TYPE_AP) | ||
1337 | iwl_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, | ||
1338 | header->addr2); | ||
1339 | iwl_handle_data_packet(priv, 0, include_phy, rxb, &rx_status); | ||
1340 | break; | ||
1341 | |||
1342 | case IEEE80211_FTYPE_CTL: | ||
1343 | switch (fc & IEEE80211_FCTL_STYPE) { | ||
1344 | case IEEE80211_STYPE_BACK_REQ: | ||
1345 | IWL_DEBUG_HT("IEEE80211_STYPE_BACK_REQ arrived\n"); | ||
1346 | iwl_handle_data_packet(priv, 0, include_phy, | ||
1347 | rxb, &rx_status); | ||
1348 | break; | ||
1349 | default: | ||
1350 | break; | ||
1351 | } | ||
1352 | break; | ||
1353 | |||
1354 | case IEEE80211_FTYPE_DATA: { | ||
1355 | DECLARE_MAC_BUF(mac1); | ||
1356 | DECLARE_MAC_BUF(mac2); | ||
1357 | DECLARE_MAC_BUF(mac3); | ||
1358 | |||
1359 | if (priv->iw_mode == IEEE80211_IF_TYPE_AP) | ||
1360 | iwl_update_ps_mode(priv, fc & IEEE80211_FCTL_PM, | ||
1361 | header->addr2); | ||
1362 | |||
1363 | if (unlikely(!network_packet)) | ||
1364 | IWL_DEBUG_DROP("Dropping (non network): " | ||
1365 | "%s, %s, %s\n", | ||
1366 | print_mac(mac1, header->addr1), | ||
1367 | print_mac(mac2, header->addr2), | ||
1368 | print_mac(mac3, header->addr3)); | ||
1369 | else if (unlikely(iwl_is_duplicate_packet(priv, header))) | ||
1370 | IWL_DEBUG_DROP("Dropping (dup): %s, %s, %s\n", | ||
1371 | print_mac(mac1, header->addr1), | ||
1372 | print_mac(mac2, header->addr2), | ||
1373 | print_mac(mac3, header->addr3)); | ||
1374 | else | ||
1375 | iwl_handle_data_packet(priv, 1, include_phy, rxb, | ||
1376 | &rx_status); | ||
1377 | break; | ||
1378 | } | ||
1379 | default: | ||
1380 | break; | ||
1381 | |||
1382 | } | ||
1383 | } | ||
1384 | EXPORT_SYMBOL(iwl_rx_reply_rx); | ||
1385 | |||
1386 | /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). | ||
1387 | * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ | ||
1388 | void iwl_rx_reply_rx_phy(struct iwl_priv *priv, | ||
1389 | struct iwl_rx_mem_buffer *rxb) | ||
1390 | { | ||
1391 | struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; | ||
1392 | priv->last_phy_res[0] = 1; | ||
1393 | memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), | ||
1394 | sizeof(struct iwl4965_rx_phy_res)); | ||
1395 | } | ||
1396 | EXPORT_SYMBOL(iwl_rx_reply_rx_phy); | ||