diff options
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-4965.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 436 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 26 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.c | 45 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-rx.c | 411 |
8 files changed, 470 insertions, 472 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index cee31cdf0a22..af48d07bb29d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c | |||
@@ -1881,7 +1881,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, | |||
1881 | info->status.rates[0].count = tx_resp->failure_frame + 1; | 1881 | info->status.rates[0].count = tx_resp->failure_frame + 1; |
1882 | info->flags &= ~IEEE80211_TX_CTL_AMPDU; | 1882 | info->flags &= ~IEEE80211_TX_CTL_AMPDU; |
1883 | info->flags |= iwl_tx_status_to_mac80211(status); | 1883 | info->flags |= iwl_tx_status_to_mac80211(status); |
1884 | iwl_hwrate_to_tx_control(priv, rate_n_flags, info); | 1884 | iwlagn_hwrate_to_tx_control(priv, rate_n_flags, info); |
1885 | /* FIXME: code repetition end */ | 1885 | /* FIXME: code repetition end */ |
1886 | 1886 | ||
1887 | IWL_DEBUG_TX_REPLY(priv, "1 Frame 0x%x failure :%d\n", | 1887 | IWL_DEBUG_TX_REPLY(priv, "1 Frame 0x%x failure :%d\n", |
@@ -2036,7 +2036,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, | |||
2036 | } else { | 2036 | } else { |
2037 | info->status.rates[0].count = tx_resp->failure_frame + 1; | 2037 | info->status.rates[0].count = tx_resp->failure_frame + 1; |
2038 | info->flags |= iwl_tx_status_to_mac80211(status); | 2038 | info->flags |= iwl_tx_status_to_mac80211(status); |
2039 | iwl_hwrate_to_tx_control(priv, | 2039 | iwlagn_hwrate_to_tx_control(priv, |
2040 | le32_to_cpu(tx_resp->rate_n_flags), | 2040 | le32_to_cpu(tx_resp->rate_n_flags), |
2041 | info); | 2041 | info); |
2042 | 2042 | ||
@@ -2102,7 +2102,7 @@ static int iwl4965_calc_rssi(struct iwl_priv *priv, | |||
2102 | static void iwl4965_rx_handler_setup(struct iwl_priv *priv) | 2102 | static void iwl4965_rx_handler_setup(struct iwl_priv *priv) |
2103 | { | 2103 | { |
2104 | /* Legacy Rx frames */ | 2104 | /* Legacy Rx frames */ |
2105 | priv->rx_handlers[REPLY_RX] = iwl_rx_reply_rx; | 2105 | priv->rx_handlers[REPLY_RX] = iwlagn_rx_reply_rx; |
2106 | /* Tx response */ | 2106 | /* Tx response */ |
2107 | priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx; | 2107 | priv->rx_handlers[REPLY_TX] = iwl4965_rx_reply_tx; |
2108 | } | 2108 | } |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 3117382cfd48..226862d3d5ac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c | |||
@@ -26,7 +26,7 @@ | |||
26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 | 26 | * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 |
27 | * | 27 | * |
28 | *****************************************************************************/ | 28 | *****************************************************************************/ |
29 | 29 | #include <linux/etherdevice.h> | |
30 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/init.h> | 32 | #include <linux/init.h> |
@@ -80,7 +80,7 @@ static int iwlagn_tx_status_reply_tx(struct iwl_priv *priv, | |||
80 | info->status.rates[0].count = tx_resp->failure_frame + 1; | 80 | info->status.rates[0].count = tx_resp->failure_frame + 1; |
81 | info->flags &= ~IEEE80211_TX_CTL_AMPDU; | 81 | info->flags &= ~IEEE80211_TX_CTL_AMPDU; |
82 | info->flags |= iwl_tx_status_to_mac80211(status); | 82 | info->flags |= iwl_tx_status_to_mac80211(status); |
83 | iwl_hwrate_to_tx_control(priv, rate_n_flags, info); | 83 | iwlagn_hwrate_to_tx_control(priv, rate_n_flags, info); |
84 | 84 | ||
85 | /* FIXME: code repetition end */ | 85 | /* FIXME: code repetition end */ |
86 | 86 | ||
@@ -225,7 +225,7 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv, | |||
225 | 225 | ||
226 | info->status.rates[0].count = tx_resp->failure_frame + 1; | 226 | info->status.rates[0].count = tx_resp->failure_frame + 1; |
227 | info->flags |= iwl_tx_status_to_mac80211(status); | 227 | info->flags |= iwl_tx_status_to_mac80211(status); |
228 | iwl_hwrate_to_tx_control(priv, | 228 | iwlagn_hwrate_to_tx_control(priv, |
229 | le32_to_cpu(tx_resp->rate_n_flags), | 229 | le32_to_cpu(tx_resp->rate_n_flags), |
230 | info); | 230 | info); |
231 | 231 | ||
@@ -709,3 +709,433 @@ int iwlagn_rxq_stop(struct iwl_priv *priv) | |||
709 | 709 | ||
710 | return 0; | 710 | return 0; |
711 | } | 711 | } |
712 | |||
713 | int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band) | ||
714 | { | ||
715 | int idx = 0; | ||
716 | int band_offset = 0; | ||
717 | |||
718 | /* HT rate format: mac80211 wants an MCS number, which is just LSB */ | ||
719 | if (rate_n_flags & RATE_MCS_HT_MSK) { | ||
720 | idx = (rate_n_flags & 0xff); | ||
721 | return idx; | ||
722 | /* Legacy rate format, search for match in table */ | ||
723 | } else { | ||
724 | if (band == IEEE80211_BAND_5GHZ) | ||
725 | band_offset = IWL_FIRST_OFDM_RATE; | ||
726 | for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++) | ||
727 | if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) | ||
728 | return idx - band_offset; | ||
729 | } | ||
730 | |||
731 | return -1; | ||
732 | } | ||
733 | |||
734 | /* Calc max signal level (dBm) among 3 possible receivers */ | ||
735 | static inline int iwlagn_calc_rssi(struct iwl_priv *priv, | ||
736 | struct iwl_rx_phy_res *rx_resp) | ||
737 | { | ||
738 | return priv->cfg->ops->utils->calc_rssi(priv, rx_resp); | ||
739 | } | ||
740 | |||
741 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
742 | /** | ||
743 | * iwlagn_dbg_report_frame - dump frame to syslog during debug sessions | ||
744 | * | ||
745 | * You may hack this function to show different aspects of received frames, | ||
746 | * including selective frame dumps. | ||
747 | * group100 parameter selects whether to show 1 out of 100 good data frames. | ||
748 | * All beacon and probe response frames are printed. | ||
749 | */ | ||
750 | static void iwlagn_dbg_report_frame(struct iwl_priv *priv, | ||
751 | struct iwl_rx_phy_res *phy_res, u16 length, | ||
752 | struct ieee80211_hdr *header, int group100) | ||
753 | { | ||
754 | u32 to_us; | ||
755 | u32 print_summary = 0; | ||
756 | u32 print_dump = 0; /* set to 1 to dump all frames' contents */ | ||
757 | u32 hundred = 0; | ||
758 | u32 dataframe = 0; | ||
759 | __le16 fc; | ||
760 | u16 seq_ctl; | ||
761 | u16 channel; | ||
762 | u16 phy_flags; | ||
763 | u32 rate_n_flags; | ||
764 | u32 tsf_low; | ||
765 | int rssi; | ||
766 | |||
767 | if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX))) | ||
768 | return; | ||
769 | |||
770 | /* MAC header */ | ||
771 | fc = header->frame_control; | ||
772 | seq_ctl = le16_to_cpu(header->seq_ctrl); | ||
773 | |||
774 | /* metadata */ | ||
775 | channel = le16_to_cpu(phy_res->channel); | ||
776 | phy_flags = le16_to_cpu(phy_res->phy_flags); | ||
777 | rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); | ||
778 | |||
779 | /* signal statistics */ | ||
780 | rssi = iwlagn_calc_rssi(priv, phy_res); | ||
781 | tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff; | ||
782 | |||
783 | to_us = !compare_ether_addr(header->addr1, priv->mac_addr); | ||
784 | |||
785 | /* if data frame is to us and all is good, | ||
786 | * (optionally) print summary for only 1 out of every 100 */ | ||
787 | if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) == | ||
788 | cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { | ||
789 | dataframe = 1; | ||
790 | if (!group100) | ||
791 | print_summary = 1; /* print each frame */ | ||
792 | else if (priv->framecnt_to_us < 100) { | ||
793 | priv->framecnt_to_us++; | ||
794 | print_summary = 0; | ||
795 | } else { | ||
796 | priv->framecnt_to_us = 0; | ||
797 | print_summary = 1; | ||
798 | hundred = 1; | ||
799 | } | ||
800 | } else { | ||
801 | /* print summary for all other frames */ | ||
802 | print_summary = 1; | ||
803 | } | ||
804 | |||
805 | if (print_summary) { | ||
806 | char *title; | ||
807 | int rate_idx; | ||
808 | u32 bitrate; | ||
809 | |||
810 | if (hundred) | ||
811 | title = "100Frames"; | ||
812 | else if (ieee80211_has_retry(fc)) | ||
813 | title = "Retry"; | ||
814 | else if (ieee80211_is_assoc_resp(fc)) | ||
815 | title = "AscRsp"; | ||
816 | else if (ieee80211_is_reassoc_resp(fc)) | ||
817 | title = "RasRsp"; | ||
818 | else if (ieee80211_is_probe_resp(fc)) { | ||
819 | title = "PrbRsp"; | ||
820 | print_dump = 1; /* dump frame contents */ | ||
821 | } else if (ieee80211_is_beacon(fc)) { | ||
822 | title = "Beacon"; | ||
823 | print_dump = 1; /* dump frame contents */ | ||
824 | } else if (ieee80211_is_atim(fc)) | ||
825 | title = "ATIM"; | ||
826 | else if (ieee80211_is_auth(fc)) | ||
827 | title = "Auth"; | ||
828 | else if (ieee80211_is_deauth(fc)) | ||
829 | title = "DeAuth"; | ||
830 | else if (ieee80211_is_disassoc(fc)) | ||
831 | title = "DisAssoc"; | ||
832 | else | ||
833 | title = "Frame"; | ||
834 | |||
835 | rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); | ||
836 | if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) { | ||
837 | bitrate = 0; | ||
838 | WARN_ON_ONCE(1); | ||
839 | } else { | ||
840 | bitrate = iwl_rates[rate_idx].ieee / 2; | ||
841 | } | ||
842 | |||
843 | /* print frame summary. | ||
844 | * MAC addresses show just the last byte (for brevity), | ||
845 | * but you can hack it to show more, if you'd like to. */ | ||
846 | if (dataframe) | ||
847 | IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, " | ||
848 | "len=%u, rssi=%d, chnl=%d, rate=%u, \n", | ||
849 | title, le16_to_cpu(fc), header->addr1[5], | ||
850 | length, rssi, channel, bitrate); | ||
851 | else { | ||
852 | /* src/dst addresses assume managed mode */ | ||
853 | IWL_DEBUG_RX(priv, "%s: 0x%04x, dst=0x%02x, src=0x%02x, " | ||
854 | "len=%u, rssi=%d, tim=%lu usec, " | ||
855 | "phy=0x%02x, chnl=%d\n", | ||
856 | title, le16_to_cpu(fc), header->addr1[5], | ||
857 | header->addr3[5], length, rssi, | ||
858 | tsf_low - priv->scan_start_tsf, | ||
859 | phy_flags, channel); | ||
860 | } | ||
861 | } | ||
862 | if (print_dump) | ||
863 | iwl_print_hex_dump(priv, IWL_DL_RX, header, length); | ||
864 | } | ||
865 | #endif | ||
866 | |||
867 | static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) | ||
868 | { | ||
869 | u32 decrypt_out = 0; | ||
870 | |||
871 | if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) == | ||
872 | RX_RES_STATUS_STATION_FOUND) | ||
873 | decrypt_out |= (RX_RES_STATUS_STATION_FOUND | | ||
874 | RX_RES_STATUS_NO_STATION_INFO_MISMATCH); | ||
875 | |||
876 | decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK); | ||
877 | |||
878 | /* packet was not encrypted */ | ||
879 | if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == | ||
880 | RX_RES_STATUS_SEC_TYPE_NONE) | ||
881 | return decrypt_out; | ||
882 | |||
883 | /* packet was encrypted with unknown alg */ | ||
884 | if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == | ||
885 | RX_RES_STATUS_SEC_TYPE_ERR) | ||
886 | return decrypt_out; | ||
887 | |||
888 | /* decryption was not done in HW */ | ||
889 | if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) != | ||
890 | RX_MPDU_RES_STATUS_DEC_DONE_MSK) | ||
891 | return decrypt_out; | ||
892 | |||
893 | switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) { | ||
894 | |||
895 | case RX_RES_STATUS_SEC_TYPE_CCMP: | ||
896 | /* alg is CCM: check MIC only */ | ||
897 | if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK)) | ||
898 | /* Bad MIC */ | ||
899 | decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; | ||
900 | else | ||
901 | decrypt_out |= RX_RES_STATUS_DECRYPT_OK; | ||
902 | |||
903 | break; | ||
904 | |||
905 | case RX_RES_STATUS_SEC_TYPE_TKIP: | ||
906 | if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) { | ||
907 | /* Bad TTAK */ | ||
908 | decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; | ||
909 | break; | ||
910 | } | ||
911 | /* fall through if TTAK OK */ | ||
912 | default: | ||
913 | if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) | ||
914 | decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; | ||
915 | else | ||
916 | decrypt_out |= RX_RES_STATUS_DECRYPT_OK; | ||
917 | break; | ||
918 | }; | ||
919 | |||
920 | IWL_DEBUG_RX(priv, "decrypt_in:0x%x decrypt_out = 0x%x\n", | ||
921 | decrypt_in, decrypt_out); | ||
922 | |||
923 | return decrypt_out; | ||
924 | } | ||
925 | |||
926 | static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, | ||
927 | struct ieee80211_hdr *hdr, | ||
928 | u16 len, | ||
929 | u32 ampdu_status, | ||
930 | struct iwl_rx_mem_buffer *rxb, | ||
931 | struct ieee80211_rx_status *stats) | ||
932 | { | ||
933 | struct sk_buff *skb; | ||
934 | int ret = 0; | ||
935 | __le16 fc = hdr->frame_control; | ||
936 | |||
937 | /* We only process data packets if the interface is open */ | ||
938 | if (unlikely(!priv->is_open)) { | ||
939 | IWL_DEBUG_DROP_LIMIT(priv, | ||
940 | "Dropping packet while interface is not open.\n"); | ||
941 | return; | ||
942 | } | ||
943 | |||
944 | /* In case of HW accelerated crypto and bad decryption, drop */ | ||
945 | if (!priv->cfg->mod_params->sw_crypto && | ||
946 | iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) | ||
947 | return; | ||
948 | |||
949 | skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC); | ||
950 | if (!skb) { | ||
951 | IWL_ERR(priv, "alloc_skb failed\n"); | ||
952 | return; | ||
953 | } | ||
954 | |||
955 | skb_reserve(skb, IWL_LINK_HDR_MAX); | ||
956 | skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); | ||
957 | |||
958 | /* mac80211 currently doesn't support paged SKB. Convert it to | ||
959 | * linear SKB for management frame and data frame requires | ||
960 | * software decryption or software defragementation. */ | ||
961 | if (ieee80211_is_mgmt(fc) || | ||
962 | ieee80211_has_protected(fc) || | ||
963 | ieee80211_has_morefrags(fc) || | ||
964 | le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG || | ||
965 | (ieee80211_is_data_qos(fc) && | ||
966 | *ieee80211_get_qos_ctl(hdr) & | ||
967 | IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)) | ||
968 | ret = skb_linearize(skb); | ||
969 | else | ||
970 | ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ? | ||
971 | 0 : -ENOMEM; | ||
972 | |||
973 | if (ret) { | ||
974 | kfree_skb(skb); | ||
975 | goto out; | ||
976 | } | ||
977 | |||
978 | /* | ||
979 | * XXX: We cannot touch the page and its virtual memory (hdr) after | ||
980 | * here. It might have already been freed by the above skb change. | ||
981 | */ | ||
982 | |||
983 | iwl_update_stats(priv, false, fc, len); | ||
984 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | ||
985 | |||
986 | ieee80211_rx(priv->hw, skb); | ||
987 | out: | ||
988 | priv->alloc_rxb_page--; | ||
989 | rxb->page = NULL; | ||
990 | } | ||
991 | |||
992 | /* Called for REPLY_RX (legacy ABG frames), or | ||
993 | * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ | ||
994 | void iwlagn_rx_reply_rx(struct iwl_priv *priv, | ||
995 | struct iwl_rx_mem_buffer *rxb) | ||
996 | { | ||
997 | struct ieee80211_hdr *header; | ||
998 | struct ieee80211_rx_status rx_status; | ||
999 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
1000 | struct iwl_rx_phy_res *phy_res; | ||
1001 | __le32 rx_pkt_status; | ||
1002 | struct iwl4965_rx_mpdu_res_start *amsdu; | ||
1003 | u32 len; | ||
1004 | u32 ampdu_status; | ||
1005 | u32 rate_n_flags; | ||
1006 | |||
1007 | /** | ||
1008 | * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently. | ||
1009 | * REPLY_RX: physical layer info is in this buffer | ||
1010 | * REPLY_RX_MPDU_CMD: physical layer info was sent in separate | ||
1011 | * command and cached in priv->last_phy_res | ||
1012 | * | ||
1013 | * Here we set up local variables depending on which command is | ||
1014 | * received. | ||
1015 | */ | ||
1016 | if (pkt->hdr.cmd == REPLY_RX) { | ||
1017 | phy_res = (struct iwl_rx_phy_res *)pkt->u.raw; | ||
1018 | header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res) | ||
1019 | + phy_res->cfg_phy_cnt); | ||
1020 | |||
1021 | len = le16_to_cpu(phy_res->byte_count); | ||
1022 | rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) + | ||
1023 | phy_res->cfg_phy_cnt + len); | ||
1024 | ampdu_status = le32_to_cpu(rx_pkt_status); | ||
1025 | } else { | ||
1026 | if (!priv->last_phy_res[0]) { | ||
1027 | IWL_ERR(priv, "MPDU frame without cached PHY data\n"); | ||
1028 | return; | ||
1029 | } | ||
1030 | phy_res = (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; | ||
1031 | amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; | ||
1032 | header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu)); | ||
1033 | len = le16_to_cpu(amsdu->byte_count); | ||
1034 | rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len); | ||
1035 | ampdu_status = iwlagn_translate_rx_status(priv, | ||
1036 | le32_to_cpu(rx_pkt_status)); | ||
1037 | } | ||
1038 | |||
1039 | if ((unlikely(phy_res->cfg_phy_cnt > 20))) { | ||
1040 | IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", | ||
1041 | phy_res->cfg_phy_cnt); | ||
1042 | return; | ||
1043 | } | ||
1044 | |||
1045 | if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || | ||
1046 | !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { | ||
1047 | IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", | ||
1048 | le32_to_cpu(rx_pkt_status)); | ||
1049 | return; | ||
1050 | } | ||
1051 | |||
1052 | /* This will be used in several places later */ | ||
1053 | rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); | ||
1054 | |||
1055 | /* rx_status carries information about the packet to mac80211 */ | ||
1056 | rx_status.mactime = le64_to_cpu(phy_res->timestamp); | ||
1057 | rx_status.freq = | ||
1058 | ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel)); | ||
1059 | rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? | ||
1060 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; | ||
1061 | rx_status.rate_idx = | ||
1062 | iwlagn_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band); | ||
1063 | rx_status.flag = 0; | ||
1064 | |||
1065 | /* TSF isn't reliable. In order to allow smooth user experience, | ||
1066 | * this W/A doesn't propagate it to the mac80211 */ | ||
1067 | /*rx_status.flag |= RX_FLAG_TSFT;*/ | ||
1068 | |||
1069 | priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp); | ||
1070 | |||
1071 | /* Find max signal strength (dBm) among 3 antenna/receiver chains */ | ||
1072 | rx_status.signal = iwlagn_calc_rssi(priv, phy_res); | ||
1073 | |||
1074 | /* Meaningful noise values are available only from beacon statistics, | ||
1075 | * which are gathered only when associated, and indicate noise | ||
1076 | * only for the associated network channel ... | ||
1077 | * Ignore these noise values while scanning (other channels) */ | ||
1078 | if (iwl_is_associated(priv) && | ||
1079 | !test_bit(STATUS_SCANNING, &priv->status)) { | ||
1080 | rx_status.noise = priv->last_rx_noise; | ||
1081 | } else { | ||
1082 | rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | ||
1083 | } | ||
1084 | |||
1085 | /* Reset beacon noise level if not associated. */ | ||
1086 | if (!iwl_is_associated(priv)) | ||
1087 | priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | ||
1088 | |||
1089 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
1090 | /* Set "1" to report good data frames in groups of 100 */ | ||
1091 | if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX)) | ||
1092 | iwlagn_dbg_report_frame(priv, phy_res, len, header, 1); | ||
1093 | #endif | ||
1094 | iwl_dbg_log_rx_data_frame(priv, len, header); | ||
1095 | IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, TSF %llu\n", | ||
1096 | rx_status.signal, rx_status.noise, | ||
1097 | (unsigned long long)rx_status.mactime); | ||
1098 | |||
1099 | /* | ||
1100 | * "antenna number" | ||
1101 | * | ||
1102 | * It seems that the antenna field in the phy flags value | ||
1103 | * is actually a bit field. This is undefined by radiotap, | ||
1104 | * it wants an actual antenna number but I always get "7" | ||
1105 | * for most legacy frames I receive indicating that the | ||
1106 | * same frame was received on all three RX chains. | ||
1107 | * | ||
1108 | * I think this field should be removed in favor of a | ||
1109 | * new 802.11n radiotap field "RX chains" that is defined | ||
1110 | * as a bitmask. | ||
1111 | */ | ||
1112 | rx_status.antenna = | ||
1113 | (le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK) | ||
1114 | >> RX_RES_PHY_FLAGS_ANTENNA_POS; | ||
1115 | |||
1116 | /* set the preamble flag if appropriate */ | ||
1117 | if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) | ||
1118 | rx_status.flag |= RX_FLAG_SHORTPRE; | ||
1119 | |||
1120 | /* Set up the HT phy flags */ | ||
1121 | if (rate_n_flags & RATE_MCS_HT_MSK) | ||
1122 | rx_status.flag |= RX_FLAG_HT; | ||
1123 | if (rate_n_flags & RATE_MCS_HT40_MSK) | ||
1124 | rx_status.flag |= RX_FLAG_40MHZ; | ||
1125 | if (rate_n_flags & RATE_MCS_SGI_MSK) | ||
1126 | rx_status.flag |= RX_FLAG_SHORT_GI; | ||
1127 | |||
1128 | iwlagn_pass_packet_to_mac80211(priv, header, len, ampdu_status, | ||
1129 | rxb, &rx_status); | ||
1130 | } | ||
1131 | |||
1132 | /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). | ||
1133 | * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ | ||
1134 | void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv, | ||
1135 | struct iwl_rx_mem_buffer *rxb) | ||
1136 | { | ||
1137 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
1138 | priv->last_phy_res[0] = 1; | ||
1139 | memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), | ||
1140 | sizeof(struct iwl_rx_phy_res)); | ||
1141 | } | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 4e4b70d10804..257e4aff3d96 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include "iwl-io.h" | 38 | #include "iwl-io.h" |
39 | #include "iwl-helpers.h" | 39 | #include "iwl-helpers.h" |
40 | #include "iwl-agn-hw.h" | 40 | #include "iwl-agn-hw.h" |
41 | #include "iwl-agn.h" | ||
41 | 42 | ||
42 | /* | 43 | /* |
43 | * mac80211 queues, ACs, hardware queues, FIFOs. | 44 | * mac80211 queues, ACs, hardware queues, FIFOs. |
@@ -1206,7 +1207,7 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv, | |||
1206 | info->flags |= IEEE80211_TX_STAT_AMPDU; | 1207 | info->flags |= IEEE80211_TX_STAT_AMPDU; |
1207 | info->status.ampdu_ack_map = successes; | 1208 | info->status.ampdu_ack_map = successes; |
1208 | info->status.ampdu_ack_len = agg->frame_count; | 1209 | info->status.ampdu_ack_len = agg->frame_count; |
1209 | iwl_hwrate_to_tx_control(priv, agg->rate_n_flags, info); | 1210 | iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info); |
1210 | 1211 | ||
1211 | IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", (unsigned long long)bitmap); | 1212 | IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", (unsigned long long)bitmap); |
1212 | 1213 | ||
@@ -1214,6 +1215,29 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv, | |||
1214 | } | 1215 | } |
1215 | 1216 | ||
1216 | /** | 1217 | /** |
1218 | * translate ucode response to mac80211 tx status control values | ||
1219 | */ | ||
1220 | void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, | ||
1221 | struct ieee80211_tx_info *info) | ||
1222 | { | ||
1223 | struct ieee80211_tx_rate *r = &info->control.rates[0]; | ||
1224 | |||
1225 | info->antenna_sel_tx = | ||
1226 | ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); | ||
1227 | if (rate_n_flags & RATE_MCS_HT_MSK) | ||
1228 | r->flags |= IEEE80211_TX_RC_MCS; | ||
1229 | if (rate_n_flags & RATE_MCS_GF_MSK) | ||
1230 | r->flags |= IEEE80211_TX_RC_GREEN_FIELD; | ||
1231 | if (rate_n_flags & RATE_MCS_HT40_MSK) | ||
1232 | r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||
1233 | if (rate_n_flags & RATE_MCS_DUP_MSK) | ||
1234 | r->flags |= IEEE80211_TX_RC_DUP_DATA; | ||
1235 | if (rate_n_flags & RATE_MCS_SGI_MSK) | ||
1236 | r->flags |= IEEE80211_TX_RC_SHORT_GI; | ||
1237 | r->idx = iwlagn_hwrate_to_mac80211_idx(rate_n_flags, info->band); | ||
1238 | } | ||
1239 | |||
1240 | /** | ||
1217 | * iwlagn_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA | 1241 | * iwlagn_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA |
1218 | * | 1242 | * |
1219 | * Handles block-acknowledge notification from device, which reports success | 1243 | * Handles block-acknowledge notification from device, which reports success |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index d9a287b639bf..bc08e9bdf9ac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -884,8 +884,8 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv) | |||
884 | priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = | 884 | priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = |
885 | iwl_rx_missed_beacon_notif; | 885 | iwl_rx_missed_beacon_notif; |
886 | /* Rx handlers */ | 886 | /* Rx handlers */ |
887 | priv->rx_handlers[REPLY_RX_PHY_CMD] = iwl_rx_reply_rx_phy; | 887 | priv->rx_handlers[REPLY_RX_PHY_CMD] = iwlagn_rx_reply_rx_phy; |
888 | priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwl_rx_reply_rx; | 888 | priv->rx_handlers[REPLY_RX_MPDU_CMD] = iwlagn_rx_reply_rx; |
889 | /* block ack */ | 889 | /* block ack */ |
890 | priv->rx_handlers[REPLY_COMPRESSED_BA] = iwlagn_rx_reply_compressed_ba; | 890 | priv->rx_handlers[REPLY_COMPRESSED_BA] = iwlagn_rx_reply_compressed_ba; |
891 | /* Set up hardware specific Rx handlers */ | 891 | /* Set up hardware specific Rx handlers */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h index 48f7de0914cb..5ad14055eda3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn.h | |||
@@ -124,8 +124,15 @@ void iwlagn_rx_replenish(struct iwl_priv *priv); | |||
124 | void iwlagn_rx_replenish_now(struct iwl_priv *priv); | 124 | void iwlagn_rx_replenish_now(struct iwl_priv *priv); |
125 | void iwlagn_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq); | 125 | void iwlagn_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq); |
126 | int iwlagn_rxq_stop(struct iwl_priv *priv); | 126 | int iwlagn_rxq_stop(struct iwl_priv *priv); |
127 | int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band); | ||
128 | void iwlagn_rx_reply_rx(struct iwl_priv *priv, | ||
129 | struct iwl_rx_mem_buffer *rxb); | ||
130 | void iwlagn_rx_reply_rx_phy(struct iwl_priv *priv, | ||
131 | struct iwl_rx_mem_buffer *rxb); | ||
127 | 132 | ||
128 | /* tx */ | 133 | /* tx */ |
134 | void iwlagn_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, | ||
135 | struct ieee80211_tx_info *info); | ||
129 | int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); | 136 | int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb); |
130 | int iwlagn_tx_agg_start(struct iwl_priv *priv, | 137 | int iwlagn_tx_agg_start(struct iwl_priv *priv, |
131 | const u8 *ra, u16 tid, u16 *ssn); | 138 | const u8 *ra, u16 tid, u16 *ssn); |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 0dc41d84dc15..6fe785380824 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c | |||
@@ -140,30 +140,6 @@ const struct iwl_rate_info iwl_rates[IWL_RATE_COUNT] = { | |||
140 | }; | 140 | }; |
141 | EXPORT_SYMBOL(iwl_rates); | 141 | EXPORT_SYMBOL(iwl_rates); |
142 | 142 | ||
143 | /** | ||
144 | * translate ucode response to mac80211 tx status control values | ||
145 | */ | ||
146 | void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, | ||
147 | struct ieee80211_tx_info *info) | ||
148 | { | ||
149 | struct ieee80211_tx_rate *r = &info->control.rates[0]; | ||
150 | |||
151 | info->antenna_sel_tx = | ||
152 | ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); | ||
153 | if (rate_n_flags & RATE_MCS_HT_MSK) | ||
154 | r->flags |= IEEE80211_TX_RC_MCS; | ||
155 | if (rate_n_flags & RATE_MCS_GF_MSK) | ||
156 | r->flags |= IEEE80211_TX_RC_GREEN_FIELD; | ||
157 | if (rate_n_flags & RATE_MCS_HT40_MSK) | ||
158 | r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; | ||
159 | if (rate_n_flags & RATE_MCS_DUP_MSK) | ||
160 | r->flags |= IEEE80211_TX_RC_DUP_DATA; | ||
161 | if (rate_n_flags & RATE_MCS_SGI_MSK) | ||
162 | r->flags |= IEEE80211_TX_RC_SHORT_GI; | ||
163 | r->idx = iwl_hwrate_to_mac80211_idx(rate_n_flags, info->band); | ||
164 | } | ||
165 | EXPORT_SYMBOL(iwl_hwrate_to_tx_control); | ||
166 | |||
167 | int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) | 143 | int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) |
168 | { | 144 | { |
169 | int idx = 0; | 145 | int idx = 0; |
@@ -195,27 +171,6 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) | |||
195 | } | 171 | } |
196 | EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx); | 172 | EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx); |
197 | 173 | ||
198 | int iwl_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band) | ||
199 | { | ||
200 | int idx = 0; | ||
201 | int band_offset = 0; | ||
202 | |||
203 | /* HT rate format: mac80211 wants an MCS number, which is just LSB */ | ||
204 | if (rate_n_flags & RATE_MCS_HT_MSK) { | ||
205 | idx = (rate_n_flags & 0xff); | ||
206 | return idx; | ||
207 | /* Legacy rate format, search for match in table */ | ||
208 | } else { | ||
209 | if (band == IEEE80211_BAND_5GHZ) | ||
210 | band_offset = IWL_FIRST_OFDM_RATE; | ||
211 | for (idx = band_offset; idx < IWL_RATE_COUNT_LEGACY; idx++) | ||
212 | if (iwl_rates[idx].plcp == (rate_n_flags & 0xFF)) | ||
213 | return idx - band_offset; | ||
214 | } | ||
215 | |||
216 | return -1; | ||
217 | } | ||
218 | |||
219 | u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant) | 174 | u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant) |
220 | { | 175 | { |
221 | int i; | 176 | int i; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 7c6ac34940fe..22f84f3c3c40 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h | |||
@@ -467,10 +467,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force); | |||
467 | * Rate | 467 | * Rate |
468 | ******************************************************************************/ | 468 | ******************************************************************************/ |
469 | 469 | ||
470 | void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, | ||
471 | struct ieee80211_tx_info *info); | ||
472 | int iwl_hwrate_to_plcp_idx(u32 rate_n_flags); | 470 | int iwl_hwrate_to_plcp_idx(u32 rate_n_flags); |
473 | int iwl_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band); | ||
474 | 471 | ||
475 | u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv); | 472 | u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv); |
476 | 473 | ||
@@ -670,10 +667,6 @@ extern int iwl_send_statistics_request(struct iwl_priv *priv, | |||
670 | extern int iwl_verify_ucode(struct iwl_priv *priv); | 667 | extern int iwl_verify_ucode(struct iwl_priv *priv); |
671 | extern int iwl_send_lq_cmd(struct iwl_priv *priv, | 668 | extern int iwl_send_lq_cmd(struct iwl_priv *priv, |
672 | struct iwl_link_quality_cmd *lq, u8 flags, bool init); | 669 | struct iwl_link_quality_cmd *lq, u8 flags, bool init); |
673 | extern void iwl_rx_reply_rx(struct iwl_priv *priv, | ||
674 | struct iwl_rx_mem_buffer *rxb); | ||
675 | extern void iwl_rx_reply_rx_phy(struct iwl_priv *priv, | ||
676 | struct iwl_rx_mem_buffer *rxb); | ||
677 | void iwl_apm_stop(struct iwl_priv *priv); | 670 | void iwl_apm_stop(struct iwl_priv *priv); |
678 | int iwl_apm_init(struct iwl_priv *priv); | 671 | int iwl_apm_init(struct iwl_priv *priv); |
679 | 672 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 45230c6a7899..3a4313841fe7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c | |||
@@ -489,139 +489,6 @@ void iwl_reply_statistics(struct iwl_priv *priv, | |||
489 | } | 489 | } |
490 | EXPORT_SYMBOL(iwl_reply_statistics); | 490 | EXPORT_SYMBOL(iwl_reply_statistics); |
491 | 491 | ||
492 | /* Calc max signal level (dBm) among 3 possible receivers */ | ||
493 | static inline int iwl_calc_rssi(struct iwl_priv *priv, | ||
494 | struct iwl_rx_phy_res *rx_resp) | ||
495 | { | ||
496 | return priv->cfg->ops->utils->calc_rssi(priv, rx_resp); | ||
497 | } | ||
498 | |||
499 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
500 | /** | ||
501 | * iwl_dbg_report_frame - dump frame to syslog during debug sessions | ||
502 | * | ||
503 | * You may hack this function to show different aspects of received frames, | ||
504 | * including selective frame dumps. | ||
505 | * group100 parameter selects whether to show 1 out of 100 good data frames. | ||
506 | * All beacon and probe response frames are printed. | ||
507 | */ | ||
508 | static void iwl_dbg_report_frame(struct iwl_priv *priv, | ||
509 | struct iwl_rx_phy_res *phy_res, u16 length, | ||
510 | struct ieee80211_hdr *header, int group100) | ||
511 | { | ||
512 | u32 to_us; | ||
513 | u32 print_summary = 0; | ||
514 | u32 print_dump = 0; /* set to 1 to dump all frames' contents */ | ||
515 | u32 hundred = 0; | ||
516 | u32 dataframe = 0; | ||
517 | __le16 fc; | ||
518 | u16 seq_ctl; | ||
519 | u16 channel; | ||
520 | u16 phy_flags; | ||
521 | u32 rate_n_flags; | ||
522 | u32 tsf_low; | ||
523 | int rssi; | ||
524 | |||
525 | if (likely(!(iwl_get_debug_level(priv) & IWL_DL_RX))) | ||
526 | return; | ||
527 | |||
528 | /* MAC header */ | ||
529 | fc = header->frame_control; | ||
530 | seq_ctl = le16_to_cpu(header->seq_ctrl); | ||
531 | |||
532 | /* metadata */ | ||
533 | channel = le16_to_cpu(phy_res->channel); | ||
534 | phy_flags = le16_to_cpu(phy_res->phy_flags); | ||
535 | rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); | ||
536 | |||
537 | /* signal statistics */ | ||
538 | rssi = iwl_calc_rssi(priv, phy_res); | ||
539 | tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff; | ||
540 | |||
541 | to_us = !compare_ether_addr(header->addr1, priv->mac_addr); | ||
542 | |||
543 | /* if data frame is to us and all is good, | ||
544 | * (optionally) print summary for only 1 out of every 100 */ | ||
545 | if (to_us && (fc & ~cpu_to_le16(IEEE80211_FCTL_PROTECTED)) == | ||
546 | cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FTYPE_DATA)) { | ||
547 | dataframe = 1; | ||
548 | if (!group100) | ||
549 | print_summary = 1; /* print each frame */ | ||
550 | else if (priv->framecnt_to_us < 100) { | ||
551 | priv->framecnt_to_us++; | ||
552 | print_summary = 0; | ||
553 | } else { | ||
554 | priv->framecnt_to_us = 0; | ||
555 | print_summary = 1; | ||
556 | hundred = 1; | ||
557 | } | ||
558 | } else { | ||
559 | /* print summary for all other frames */ | ||
560 | print_summary = 1; | ||
561 | } | ||
562 | |||
563 | if (print_summary) { | ||
564 | char *title; | ||
565 | int rate_idx; | ||
566 | u32 bitrate; | ||
567 | |||
568 | if (hundred) | ||
569 | title = "100Frames"; | ||
570 | else if (ieee80211_has_retry(fc)) | ||
571 | title = "Retry"; | ||
572 | else if (ieee80211_is_assoc_resp(fc)) | ||
573 | title = "AscRsp"; | ||
574 | else if (ieee80211_is_reassoc_resp(fc)) | ||
575 | title = "RasRsp"; | ||
576 | else if (ieee80211_is_probe_resp(fc)) { | ||
577 | title = "PrbRsp"; | ||
578 | print_dump = 1; /* dump frame contents */ | ||
579 | } else if (ieee80211_is_beacon(fc)) { | ||
580 | title = "Beacon"; | ||
581 | print_dump = 1; /* dump frame contents */ | ||
582 | } else if (ieee80211_is_atim(fc)) | ||
583 | title = "ATIM"; | ||
584 | else if (ieee80211_is_auth(fc)) | ||
585 | title = "Auth"; | ||
586 | else if (ieee80211_is_deauth(fc)) | ||
587 | title = "DeAuth"; | ||
588 | else if (ieee80211_is_disassoc(fc)) | ||
589 | title = "DisAssoc"; | ||
590 | else | ||
591 | title = "Frame"; | ||
592 | |||
593 | rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); | ||
594 | if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) { | ||
595 | bitrate = 0; | ||
596 | WARN_ON_ONCE(1); | ||
597 | } else { | ||
598 | bitrate = iwl_rates[rate_idx].ieee / 2; | ||
599 | } | ||
600 | |||
601 | /* print frame summary. | ||
602 | * MAC addresses show just the last byte (for brevity), | ||
603 | * but you can hack it to show more, if you'd like to. */ | ||
604 | if (dataframe) | ||
605 | IWL_DEBUG_RX(priv, "%s: mhd=0x%04x, dst=0x%02x, " | ||
606 | "len=%u, rssi=%d, chnl=%d, rate=%u, \n", | ||
607 | title, le16_to_cpu(fc), header->addr1[5], | ||
608 | length, rssi, channel, bitrate); | ||
609 | else { | ||
610 | /* src/dst addresses assume managed mode */ | ||
611 | IWL_DEBUG_RX(priv, "%s: 0x%04x, dst=0x%02x, src=0x%02x, " | ||
612 | "len=%u, rssi=%d, tim=%lu usec, " | ||
613 | "phy=0x%02x, chnl=%d\n", | ||
614 | title, le16_to_cpu(fc), header->addr1[5], | ||
615 | header->addr3[5], length, rssi, | ||
616 | tsf_low - priv->scan_start_tsf, | ||
617 | phy_flags, channel); | ||
618 | } | ||
619 | } | ||
620 | if (print_dump) | ||
621 | iwl_print_hex_dump(priv, IWL_DL_RX, header, length); | ||
622 | } | ||
623 | #endif | ||
624 | |||
625 | /* | 492 | /* |
626 | * returns non-zero if packet should be dropped | 493 | * returns non-zero if packet should be dropped |
627 | */ | 494 | */ |
@@ -669,281 +536,3 @@ int iwl_set_decrypted_flag(struct iwl_priv *priv, | |||
669 | return 0; | 536 | return 0; |
670 | } | 537 | } |
671 | EXPORT_SYMBOL(iwl_set_decrypted_flag); | 538 | EXPORT_SYMBOL(iwl_set_decrypted_flag); |
672 | |||
673 | static u32 iwl_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) | ||
674 | { | ||
675 | u32 decrypt_out = 0; | ||
676 | |||
677 | if ((decrypt_in & RX_RES_STATUS_STATION_FOUND) == | ||
678 | RX_RES_STATUS_STATION_FOUND) | ||
679 | decrypt_out |= (RX_RES_STATUS_STATION_FOUND | | ||
680 | RX_RES_STATUS_NO_STATION_INFO_MISMATCH); | ||
681 | |||
682 | decrypt_out |= (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK); | ||
683 | |||
684 | /* packet was not encrypted */ | ||
685 | if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == | ||
686 | RX_RES_STATUS_SEC_TYPE_NONE) | ||
687 | return decrypt_out; | ||
688 | |||
689 | /* packet was encrypted with unknown alg */ | ||
690 | if ((decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) == | ||
691 | RX_RES_STATUS_SEC_TYPE_ERR) | ||
692 | return decrypt_out; | ||
693 | |||
694 | /* decryption was not done in HW */ | ||
695 | if ((decrypt_in & RX_MPDU_RES_STATUS_DEC_DONE_MSK) != | ||
696 | RX_MPDU_RES_STATUS_DEC_DONE_MSK) | ||
697 | return decrypt_out; | ||
698 | |||
699 | switch (decrypt_in & RX_RES_STATUS_SEC_TYPE_MSK) { | ||
700 | |||
701 | case RX_RES_STATUS_SEC_TYPE_CCMP: | ||
702 | /* alg is CCM: check MIC only */ | ||
703 | if (!(decrypt_in & RX_MPDU_RES_STATUS_MIC_OK)) | ||
704 | /* Bad MIC */ | ||
705 | decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; | ||
706 | else | ||
707 | decrypt_out |= RX_RES_STATUS_DECRYPT_OK; | ||
708 | |||
709 | break; | ||
710 | |||
711 | case RX_RES_STATUS_SEC_TYPE_TKIP: | ||
712 | if (!(decrypt_in & RX_MPDU_RES_STATUS_TTAK_OK)) { | ||
713 | /* Bad TTAK */ | ||
714 | decrypt_out |= RX_RES_STATUS_BAD_KEY_TTAK; | ||
715 | break; | ||
716 | } | ||
717 | /* fall through if TTAK OK */ | ||
718 | default: | ||
719 | if (!(decrypt_in & RX_MPDU_RES_STATUS_ICV_OK)) | ||
720 | decrypt_out |= RX_RES_STATUS_BAD_ICV_MIC; | ||
721 | else | ||
722 | decrypt_out |= RX_RES_STATUS_DECRYPT_OK; | ||
723 | break; | ||
724 | }; | ||
725 | |||
726 | IWL_DEBUG_RX(priv, "decrypt_in:0x%x decrypt_out = 0x%x\n", | ||
727 | decrypt_in, decrypt_out); | ||
728 | |||
729 | return decrypt_out; | ||
730 | } | ||
731 | |||
732 | static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, | ||
733 | struct ieee80211_hdr *hdr, | ||
734 | u16 len, | ||
735 | u32 ampdu_status, | ||
736 | struct iwl_rx_mem_buffer *rxb, | ||
737 | struct ieee80211_rx_status *stats) | ||
738 | { | ||
739 | struct sk_buff *skb; | ||
740 | int ret = 0; | ||
741 | __le16 fc = hdr->frame_control; | ||
742 | |||
743 | /* We only process data packets if the interface is open */ | ||
744 | if (unlikely(!priv->is_open)) { | ||
745 | IWL_DEBUG_DROP_LIMIT(priv, | ||
746 | "Dropping packet while interface is not open.\n"); | ||
747 | return; | ||
748 | } | ||
749 | |||
750 | /* In case of HW accelerated crypto and bad decryption, drop */ | ||
751 | if (!priv->cfg->mod_params->sw_crypto && | ||
752 | iwl_set_decrypted_flag(priv, hdr, ampdu_status, stats)) | ||
753 | return; | ||
754 | |||
755 | skb = alloc_skb(IWL_LINK_HDR_MAX * 2, GFP_ATOMIC); | ||
756 | if (!skb) { | ||
757 | IWL_ERR(priv, "alloc_skb failed\n"); | ||
758 | return; | ||
759 | } | ||
760 | |||
761 | skb_reserve(skb, IWL_LINK_HDR_MAX); | ||
762 | skb_add_rx_frag(skb, 0, rxb->page, (void *)hdr - rxb_addr(rxb), len); | ||
763 | |||
764 | /* mac80211 currently doesn't support paged SKB. Convert it to | ||
765 | * linear SKB for management frame and data frame requires | ||
766 | * software decryption or software defragementation. */ | ||
767 | if (ieee80211_is_mgmt(fc) || | ||
768 | ieee80211_has_protected(fc) || | ||
769 | ieee80211_has_morefrags(fc) || | ||
770 | le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG || | ||
771 | (ieee80211_is_data_qos(fc) && | ||
772 | *ieee80211_get_qos_ctl(hdr) & | ||
773 | IEEE80211_QOS_CONTROL_A_MSDU_PRESENT)) | ||
774 | ret = skb_linearize(skb); | ||
775 | else | ||
776 | ret = __pskb_pull_tail(skb, min_t(u16, IWL_LINK_HDR_MAX, len)) ? | ||
777 | 0 : -ENOMEM; | ||
778 | |||
779 | if (ret) { | ||
780 | kfree_skb(skb); | ||
781 | goto out; | ||
782 | } | ||
783 | |||
784 | /* | ||
785 | * XXX: We cannot touch the page and its virtual memory (hdr) after | ||
786 | * here. It might have already been freed by the above skb change. | ||
787 | */ | ||
788 | |||
789 | iwl_update_stats(priv, false, fc, len); | ||
790 | memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); | ||
791 | |||
792 | ieee80211_rx(priv->hw, skb); | ||
793 | out: | ||
794 | priv->alloc_rxb_page--; | ||
795 | rxb->page = NULL; | ||
796 | } | ||
797 | |||
798 | /* Called for REPLY_RX (legacy ABG frames), or | ||
799 | * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ | ||
800 | void iwl_rx_reply_rx(struct iwl_priv *priv, | ||
801 | struct iwl_rx_mem_buffer *rxb) | ||
802 | { | ||
803 | struct ieee80211_hdr *header; | ||
804 | struct ieee80211_rx_status rx_status; | ||
805 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
806 | struct iwl_rx_phy_res *phy_res; | ||
807 | __le32 rx_pkt_status; | ||
808 | struct iwl4965_rx_mpdu_res_start *amsdu; | ||
809 | u32 len; | ||
810 | u32 ampdu_status; | ||
811 | u32 rate_n_flags; | ||
812 | |||
813 | /** | ||
814 | * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently. | ||
815 | * REPLY_RX: physical layer info is in this buffer | ||
816 | * REPLY_RX_MPDU_CMD: physical layer info was sent in separate | ||
817 | * command and cached in priv->last_phy_res | ||
818 | * | ||
819 | * Here we set up local variables depending on which command is | ||
820 | * received. | ||
821 | */ | ||
822 | if (pkt->hdr.cmd == REPLY_RX) { | ||
823 | phy_res = (struct iwl_rx_phy_res *)pkt->u.raw; | ||
824 | header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*phy_res) | ||
825 | + phy_res->cfg_phy_cnt); | ||
826 | |||
827 | len = le16_to_cpu(phy_res->byte_count); | ||
828 | rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*phy_res) + | ||
829 | phy_res->cfg_phy_cnt + len); | ||
830 | ampdu_status = le32_to_cpu(rx_pkt_status); | ||
831 | } else { | ||
832 | if (!priv->last_phy_res[0]) { | ||
833 | IWL_ERR(priv, "MPDU frame without cached PHY data\n"); | ||
834 | return; | ||
835 | } | ||
836 | phy_res = (struct iwl_rx_phy_res *)&priv->last_phy_res[1]; | ||
837 | amsdu = (struct iwl4965_rx_mpdu_res_start *)pkt->u.raw; | ||
838 | header = (struct ieee80211_hdr *)(pkt->u.raw + sizeof(*amsdu)); | ||
839 | len = le16_to_cpu(amsdu->byte_count); | ||
840 | rx_pkt_status = *(__le32 *)(pkt->u.raw + sizeof(*amsdu) + len); | ||
841 | ampdu_status = iwl_translate_rx_status(priv, | ||
842 | le32_to_cpu(rx_pkt_status)); | ||
843 | } | ||
844 | |||
845 | if ((unlikely(phy_res->cfg_phy_cnt > 20))) { | ||
846 | IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n", | ||
847 | phy_res->cfg_phy_cnt); | ||
848 | return; | ||
849 | } | ||
850 | |||
851 | if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) || | ||
852 | !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) { | ||
853 | IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n", | ||
854 | le32_to_cpu(rx_pkt_status)); | ||
855 | return; | ||
856 | } | ||
857 | |||
858 | /* This will be used in several places later */ | ||
859 | rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); | ||
860 | |||
861 | /* rx_status carries information about the packet to mac80211 */ | ||
862 | rx_status.mactime = le64_to_cpu(phy_res->timestamp); | ||
863 | rx_status.freq = | ||
864 | ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel)); | ||
865 | rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ? | ||
866 | IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ; | ||
867 | rx_status.rate_idx = | ||
868 | iwl_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band); | ||
869 | rx_status.flag = 0; | ||
870 | |||
871 | /* TSF isn't reliable. In order to allow smooth user experience, | ||
872 | * this W/A doesn't propagate it to the mac80211 */ | ||
873 | /*rx_status.flag |= RX_FLAG_TSFT;*/ | ||
874 | |||
875 | priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp); | ||
876 | |||
877 | /* Find max signal strength (dBm) among 3 antenna/receiver chains */ | ||
878 | rx_status.signal = iwl_calc_rssi(priv, phy_res); | ||
879 | |||
880 | /* Meaningful noise values are available only from beacon statistics, | ||
881 | * which are gathered only when associated, and indicate noise | ||
882 | * only for the associated network channel ... | ||
883 | * Ignore these noise values while scanning (other channels) */ | ||
884 | if (iwl_is_associated(priv) && | ||
885 | !test_bit(STATUS_SCANNING, &priv->status)) { | ||
886 | rx_status.noise = priv->last_rx_noise; | ||
887 | } else { | ||
888 | rx_status.noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | ||
889 | } | ||
890 | |||
891 | /* Reset beacon noise level if not associated. */ | ||
892 | if (!iwl_is_associated(priv)) | ||
893 | priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; | ||
894 | |||
895 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
896 | /* Set "1" to report good data frames in groups of 100 */ | ||
897 | if (unlikely(iwl_get_debug_level(priv) & IWL_DL_RX)) | ||
898 | iwl_dbg_report_frame(priv, phy_res, len, header, 1); | ||
899 | #endif | ||
900 | iwl_dbg_log_rx_data_frame(priv, len, header); | ||
901 | IWL_DEBUG_STATS_LIMIT(priv, "Rssi %d, noise %d, TSF %llu\n", | ||
902 | rx_status.signal, rx_status.noise, | ||
903 | (unsigned long long)rx_status.mactime); | ||
904 | |||
905 | /* | ||
906 | * "antenna number" | ||
907 | * | ||
908 | * It seems that the antenna field in the phy flags value | ||
909 | * is actually a bit field. This is undefined by radiotap, | ||
910 | * it wants an actual antenna number but I always get "7" | ||
911 | * for most legacy frames I receive indicating that the | ||
912 | * same frame was received on all three RX chains. | ||
913 | * | ||
914 | * I think this field should be removed in favor of a | ||
915 | * new 802.11n radiotap field "RX chains" that is defined | ||
916 | * as a bitmask. | ||
917 | */ | ||
918 | rx_status.antenna = | ||
919 | (le16_to_cpu(phy_res->phy_flags) & RX_RES_PHY_FLAGS_ANTENNA_MSK) | ||
920 | >> RX_RES_PHY_FLAGS_ANTENNA_POS; | ||
921 | |||
922 | /* set the preamble flag if appropriate */ | ||
923 | if (phy_res->phy_flags & RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK) | ||
924 | rx_status.flag |= RX_FLAG_SHORTPRE; | ||
925 | |||
926 | /* Set up the HT phy flags */ | ||
927 | if (rate_n_flags & RATE_MCS_HT_MSK) | ||
928 | rx_status.flag |= RX_FLAG_HT; | ||
929 | if (rate_n_flags & RATE_MCS_HT40_MSK) | ||
930 | rx_status.flag |= RX_FLAG_40MHZ; | ||
931 | if (rate_n_flags & RATE_MCS_SGI_MSK) | ||
932 | rx_status.flag |= RX_FLAG_SHORT_GI; | ||
933 | |||
934 | iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status, | ||
935 | rxb, &rx_status); | ||
936 | } | ||
937 | EXPORT_SYMBOL(iwl_rx_reply_rx); | ||
938 | |||
939 | /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD). | ||
940 | * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */ | ||
941 | void iwl_rx_reply_rx_phy(struct iwl_priv *priv, | ||
942 | struct iwl_rx_mem_buffer *rxb) | ||
943 | { | ||
944 | struct iwl_rx_packet *pkt = rxb_addr(rxb); | ||
945 | priv->last_phy_res[0] = 1; | ||
946 | memcpy(&priv->last_phy_res[1], &(pkt->u.raw[0]), | ||
947 | sizeof(struct iwl_rx_phy_res)); | ||
948 | } | ||
949 | EXPORT_SYMBOL(iwl_rx_reply_rx_phy); | ||