diff options
Diffstat (limited to 'net/mac80211/util.c')
-rw-r--r-- | net/mac80211/util.c | 176 |
1 files changed, 176 insertions, 0 deletions
diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 92ea1770461b..dee17e5cbb89 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c | |||
@@ -750,6 +750,27 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata) | |||
750 | local->ops->conf_tx(local_to_hw(local), i, &qparam); | 750 | local->ops->conf_tx(local_to_hw(local), i, &qparam); |
751 | } | 751 | } |
752 | 752 | ||
753 | void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata, | ||
754 | const size_t supp_rates_len, | ||
755 | const u8 *supp_rates) | ||
756 | { | ||
757 | struct ieee80211_local *local = sdata->local; | ||
758 | int i, have_higher_than_11mbit = 0; | ||
759 | |||
760 | /* cf. IEEE 802.11 9.2.12 */ | ||
761 | for (i = 0; i < supp_rates_len; i++) | ||
762 | if ((supp_rates[i] & 0x7f) * 5 > 110) | ||
763 | have_higher_than_11mbit = 1; | ||
764 | |||
765 | if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && | ||
766 | have_higher_than_11mbit) | ||
767 | sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | ||
768 | else | ||
769 | sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; | ||
770 | |||
771 | ieee80211_set_wmm_default(sdata); | ||
772 | } | ||
773 | |||
753 | void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, | 774 | void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, |
754 | int encrypt) | 775 | int encrypt) |
755 | { | 776 | { |
@@ -816,3 +837,158 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local, | |||
816 | mandatory_rates |= BIT(i); | 837 | mandatory_rates |= BIT(i); |
817 | return mandatory_rates; | 838 | return mandatory_rates; |
818 | } | 839 | } |
840 | |||
841 | void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata, | ||
842 | u16 transaction, u16 auth_alg, | ||
843 | u8 *extra, size_t extra_len, | ||
844 | const u8 *bssid, int encrypt) | ||
845 | { | ||
846 | struct ieee80211_local *local = sdata->local; | ||
847 | struct sk_buff *skb; | ||
848 | struct ieee80211_mgmt *mgmt; | ||
849 | const u8 *ie_auth = NULL; | ||
850 | int ie_auth_len = 0; | ||
851 | |||
852 | if (sdata->vif.type == NL80211_IFTYPE_STATION) { | ||
853 | ie_auth_len = sdata->u.mgd.ie_auth_len; | ||
854 | ie_auth = sdata->u.mgd.ie_auth; | ||
855 | } | ||
856 | |||
857 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + | ||
858 | sizeof(*mgmt) + 6 + extra_len + ie_auth_len); | ||
859 | if (!skb) { | ||
860 | printk(KERN_DEBUG "%s: failed to allocate buffer for auth " | ||
861 | "frame\n", sdata->dev->name); | ||
862 | return; | ||
863 | } | ||
864 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
865 | |||
866 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6); | ||
867 | memset(mgmt, 0, 24 + 6); | ||
868 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
869 | IEEE80211_STYPE_AUTH); | ||
870 | if (encrypt) | ||
871 | mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); | ||
872 | memcpy(mgmt->da, bssid, ETH_ALEN); | ||
873 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
874 | memcpy(mgmt->bssid, bssid, ETH_ALEN); | ||
875 | mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg); | ||
876 | mgmt->u.auth.auth_transaction = cpu_to_le16(transaction); | ||
877 | mgmt->u.auth.status_code = cpu_to_le16(0); | ||
878 | if (extra) | ||
879 | memcpy(skb_put(skb, extra_len), extra, extra_len); | ||
880 | if (ie_auth) | ||
881 | memcpy(skb_put(skb, ie_auth_len), ie_auth, ie_auth_len); | ||
882 | |||
883 | ieee80211_tx_skb(sdata, skb, encrypt); | ||
884 | } | ||
885 | |||
886 | void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst, | ||
887 | u8 *ssid, size_t ssid_len) | ||
888 | { | ||
889 | struct ieee80211_local *local = sdata->local; | ||
890 | struct ieee80211_supported_band *sband; | ||
891 | struct sk_buff *skb; | ||
892 | struct ieee80211_mgmt *mgmt; | ||
893 | u8 *pos, *supp_rates, *esupp_rates = NULL, *extra_preq_ie = NULL; | ||
894 | int i, extra_preq_ie_len = 0; | ||
895 | |||
896 | switch (sdata->vif.type) { | ||
897 | case NL80211_IFTYPE_STATION: | ||
898 | extra_preq_ie_len = sdata->u.mgd.ie_probereq_len; | ||
899 | extra_preq_ie = sdata->u.mgd.ie_probereq; | ||
900 | break; | ||
901 | default: | ||
902 | break; | ||
903 | } | ||
904 | |||
905 | skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 + | ||
906 | extra_preq_ie_len); | ||
907 | if (!skb) { | ||
908 | printk(KERN_DEBUG "%s: failed to allocate buffer for probe " | ||
909 | "request\n", sdata->dev->name); | ||
910 | return; | ||
911 | } | ||
912 | skb_reserve(skb, local->hw.extra_tx_headroom); | ||
913 | |||
914 | mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24); | ||
915 | memset(mgmt, 0, 24); | ||
916 | mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | | ||
917 | IEEE80211_STYPE_PROBE_REQ); | ||
918 | memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN); | ||
919 | if (dst) { | ||
920 | memcpy(mgmt->da, dst, ETH_ALEN); | ||
921 | memcpy(mgmt->bssid, dst, ETH_ALEN); | ||
922 | } else { | ||
923 | memset(mgmt->da, 0xff, ETH_ALEN); | ||
924 | memset(mgmt->bssid, 0xff, ETH_ALEN); | ||
925 | } | ||
926 | pos = skb_put(skb, 2 + ssid_len); | ||
927 | *pos++ = WLAN_EID_SSID; | ||
928 | *pos++ = ssid_len; | ||
929 | memcpy(pos, ssid, ssid_len); | ||
930 | |||
931 | supp_rates = skb_put(skb, 2); | ||
932 | supp_rates[0] = WLAN_EID_SUPP_RATES; | ||
933 | supp_rates[1] = 0; | ||
934 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
935 | |||
936 | for (i = 0; i < sband->n_bitrates; i++) { | ||
937 | struct ieee80211_rate *rate = &sband->bitrates[i]; | ||
938 | if (esupp_rates) { | ||
939 | pos = skb_put(skb, 1); | ||
940 | esupp_rates[1]++; | ||
941 | } else if (supp_rates[1] == 8) { | ||
942 | esupp_rates = skb_put(skb, 3); | ||
943 | esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES; | ||
944 | esupp_rates[1] = 1; | ||
945 | pos = &esupp_rates[2]; | ||
946 | } else { | ||
947 | pos = skb_put(skb, 1); | ||
948 | supp_rates[1]++; | ||
949 | } | ||
950 | *pos = rate->bitrate / 5; | ||
951 | } | ||
952 | |||
953 | if (extra_preq_ie) | ||
954 | memcpy(skb_put(skb, extra_preq_ie_len), extra_preq_ie, | ||
955 | extra_preq_ie_len); | ||
956 | |||
957 | ieee80211_tx_skb(sdata, skb, 0); | ||
958 | } | ||
959 | |||
960 | u32 ieee80211_sta_get_rates(struct ieee80211_local *local, | ||
961 | struct ieee802_11_elems *elems, | ||
962 | enum ieee80211_band band) | ||
963 | { | ||
964 | struct ieee80211_supported_band *sband; | ||
965 | struct ieee80211_rate *bitrates; | ||
966 | size_t num_rates; | ||
967 | u32 supp_rates; | ||
968 | int i, j; | ||
969 | sband = local->hw.wiphy->bands[band]; | ||
970 | |||
971 | if (!sband) { | ||
972 | WARN_ON(1); | ||
973 | sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; | ||
974 | } | ||
975 | |||
976 | bitrates = sband->bitrates; | ||
977 | num_rates = sband->n_bitrates; | ||
978 | supp_rates = 0; | ||
979 | for (i = 0; i < elems->supp_rates_len + | ||
980 | elems->ext_supp_rates_len; i++) { | ||
981 | u8 rate = 0; | ||
982 | int own_rate; | ||
983 | if (i < elems->supp_rates_len) | ||
984 | rate = elems->supp_rates[i]; | ||
985 | else if (elems->ext_supp_rates) | ||
986 | rate = elems->ext_supp_rates | ||
987 | [i - elems->supp_rates_len]; | ||
988 | own_rate = 5 * (rate & 0x7f); | ||
989 | for (j = 0; j < num_rates; j++) | ||
990 | if (bitrates[j].bitrate == own_rate) | ||
991 | supp_rates |= BIT(j); | ||
992 | } | ||
993 | return supp_rates; | ||
994 | } | ||