diff options
Diffstat (limited to 'net/wireless/util.c')
-rw-r--r-- | net/wireless/util.c | 194 |
1 files changed, 183 insertions, 11 deletions
diff --git a/net/wireless/util.c b/net/wireless/util.c index be75a3a0424e..2f178f73943f 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <linux/bitops.h> | 6 | #include <linux/bitops.h> |
7 | #include <linux/etherdevice.h> | 7 | #include <linux/etherdevice.h> |
8 | #include <linux/slab.h> | 8 | #include <linux/slab.h> |
9 | #include <linux/crc32.h> | ||
9 | #include <net/cfg80211.h> | 10 | #include <net/cfg80211.h> |
10 | #include <net/ip.h> | 11 | #include <net/ip.h> |
11 | #include "core.h" | 12 | #include "core.h" |
@@ -150,12 +151,19 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy) | |||
150 | set_mandatory_flags_band(wiphy->bands[band], band); | 151 | set_mandatory_flags_band(wiphy->bands[band], band); |
151 | } | 152 | } |
152 | 153 | ||
154 | bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher) | ||
155 | { | ||
156 | int i; | ||
157 | for (i = 0; i < wiphy->n_cipher_suites; i++) | ||
158 | if (cipher == wiphy->cipher_suites[i]) | ||
159 | return true; | ||
160 | return false; | ||
161 | } | ||
162 | |||
153 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | 163 | int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, |
154 | struct key_params *params, int key_idx, | 164 | struct key_params *params, int key_idx, |
155 | bool pairwise, const u8 *mac_addr) | 165 | bool pairwise, const u8 *mac_addr) |
156 | { | 166 | { |
157 | int i; | ||
158 | |||
159 | if (key_idx > 5) | 167 | if (key_idx > 5) |
160 | return -EINVAL; | 168 | return -EINVAL; |
161 | 169 | ||
@@ -225,10 +233,7 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev, | |||
225 | } | 233 | } |
226 | } | 234 | } |
227 | 235 | ||
228 | for (i = 0; i < rdev->wiphy.n_cipher_suites; i++) | 236 | if (!cfg80211_supported_cipher_suite(&rdev->wiphy, params->cipher)) |
229 | if (params->cipher == rdev->wiphy.cipher_suites[i]) | ||
230 | break; | ||
231 | if (i == rdev->wiphy.n_cipher_suites) | ||
232 | return -EINVAL; | 237 | return -EINVAL; |
233 | 238 | ||
234 | return 0; | 239 | return 0; |
@@ -391,8 +396,9 @@ int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr, | |||
391 | } | 396 | } |
392 | break; | 397 | break; |
393 | case cpu_to_le16(0): | 398 | case cpu_to_le16(0): |
394 | if (iftype != NL80211_IFTYPE_ADHOC) | 399 | if (iftype != NL80211_IFTYPE_ADHOC && |
395 | return -1; | 400 | iftype != NL80211_IFTYPE_STATION) |
401 | return -1; | ||
396 | break; | 402 | break; |
397 | } | 403 | } |
398 | 404 | ||
@@ -512,10 +518,9 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, | |||
512 | if (head_need) | 518 | if (head_need) |
513 | skb_orphan(skb); | 519 | skb_orphan(skb); |
514 | 520 | ||
515 | if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) { | 521 | if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) |
516 | pr_err("failed to reallocate Tx buffer\n"); | ||
517 | return -ENOMEM; | 522 | return -ENOMEM; |
518 | } | 523 | |
519 | skb->truesize += head_need; | 524 | skb->truesize += head_need; |
520 | } | 525 | } |
521 | 526 | ||
@@ -1044,3 +1049,170 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, | |||
1044 | 1049 | ||
1045 | return 0; | 1050 | return 0; |
1046 | } | 1051 | } |
1052 | |||
1053 | u32 ieee802_11_parse_elems_crc(u8 *start, size_t len, | ||
1054 | struct ieee802_11_elems *elems, | ||
1055 | u64 filter, u32 crc) | ||
1056 | { | ||
1057 | size_t left = len; | ||
1058 | u8 *pos = start; | ||
1059 | bool calc_crc = filter != 0; | ||
1060 | |||
1061 | memset(elems, 0, sizeof(*elems)); | ||
1062 | elems->ie_start = start; | ||
1063 | elems->total_len = len; | ||
1064 | |||
1065 | while (left >= 2) { | ||
1066 | u8 id, elen; | ||
1067 | |||
1068 | id = *pos++; | ||
1069 | elen = *pos++; | ||
1070 | left -= 2; | ||
1071 | |||
1072 | if (elen > left) | ||
1073 | break; | ||
1074 | |||
1075 | if (calc_crc && id < 64 && (filter & (1ULL << id))) | ||
1076 | crc = crc32_be(crc, pos - 2, elen + 2); | ||
1077 | |||
1078 | switch (id) { | ||
1079 | case WLAN_EID_SSID: | ||
1080 | elems->ssid = pos; | ||
1081 | elems->ssid_len = elen; | ||
1082 | break; | ||
1083 | case WLAN_EID_SUPP_RATES: | ||
1084 | elems->supp_rates = pos; | ||
1085 | elems->supp_rates_len = elen; | ||
1086 | break; | ||
1087 | case WLAN_EID_FH_PARAMS: | ||
1088 | elems->fh_params = pos; | ||
1089 | elems->fh_params_len = elen; | ||
1090 | break; | ||
1091 | case WLAN_EID_DS_PARAMS: | ||
1092 | elems->ds_params = pos; | ||
1093 | elems->ds_params_len = elen; | ||
1094 | break; | ||
1095 | case WLAN_EID_CF_PARAMS: | ||
1096 | elems->cf_params = pos; | ||
1097 | elems->cf_params_len = elen; | ||
1098 | break; | ||
1099 | case WLAN_EID_TIM: | ||
1100 | if (elen >= sizeof(struct ieee80211_tim_ie)) { | ||
1101 | elems->tim = (void *)pos; | ||
1102 | elems->tim_len = elen; | ||
1103 | } | ||
1104 | break; | ||
1105 | case WLAN_EID_IBSS_PARAMS: | ||
1106 | elems->ibss_params = pos; | ||
1107 | elems->ibss_params_len = elen; | ||
1108 | break; | ||
1109 | case WLAN_EID_CHALLENGE: | ||
1110 | elems->challenge = pos; | ||
1111 | elems->challenge_len = elen; | ||
1112 | break; | ||
1113 | case WLAN_EID_VENDOR_SPECIFIC: | ||
1114 | if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 && | ||
1115 | pos[2] == 0xf2) { | ||
1116 | /* Microsoft OUI (00:50:F2) */ | ||
1117 | |||
1118 | if (calc_crc) | ||
1119 | crc = crc32_be(crc, pos - 2, elen + 2); | ||
1120 | |||
1121 | if (pos[3] == 1) { | ||
1122 | /* OUI Type 1 - WPA IE */ | ||
1123 | elems->wpa = pos; | ||
1124 | elems->wpa_len = elen; | ||
1125 | } else if (elen >= 5 && pos[3] == 2) { | ||
1126 | /* OUI Type 2 - WMM IE */ | ||
1127 | if (pos[4] == 0) { | ||
1128 | elems->wmm_info = pos; | ||
1129 | elems->wmm_info_len = elen; | ||
1130 | } else if (pos[4] == 1) { | ||
1131 | elems->wmm_param = pos; | ||
1132 | elems->wmm_param_len = elen; | ||
1133 | } | ||
1134 | } | ||
1135 | } | ||
1136 | break; | ||
1137 | case WLAN_EID_RSN: | ||
1138 | elems->rsn = pos; | ||
1139 | elems->rsn_len = elen; | ||
1140 | break; | ||
1141 | case WLAN_EID_ERP_INFO: | ||
1142 | elems->erp_info = pos; | ||
1143 | elems->erp_info_len = elen; | ||
1144 | break; | ||
1145 | case WLAN_EID_EXT_SUPP_RATES: | ||
1146 | elems->ext_supp_rates = pos; | ||
1147 | elems->ext_supp_rates_len = elen; | ||
1148 | break; | ||
1149 | case WLAN_EID_HT_CAPABILITY: | ||
1150 | if (elen >= sizeof(struct ieee80211_ht_cap)) | ||
1151 | elems->ht_cap_elem = (void *)pos; | ||
1152 | break; | ||
1153 | case WLAN_EID_HT_INFORMATION: | ||
1154 | if (elen >= sizeof(struct ieee80211_ht_info)) | ||
1155 | elems->ht_info_elem = (void *)pos; | ||
1156 | break; | ||
1157 | case WLAN_EID_MESH_ID: | ||
1158 | elems->mesh_id = pos; | ||
1159 | elems->mesh_id_len = elen; | ||
1160 | break; | ||
1161 | case WLAN_EID_MESH_CONFIG: | ||
1162 | if (elen >= sizeof(struct ieee80211_meshconf_ie)) | ||
1163 | elems->mesh_config = (void *)pos; | ||
1164 | break; | ||
1165 | case WLAN_EID_PEER_MGMT: | ||
1166 | elems->peering = pos; | ||
1167 | elems->peering_len = elen; | ||
1168 | break; | ||
1169 | case WLAN_EID_PREQ: | ||
1170 | elems->preq = pos; | ||
1171 | elems->preq_len = elen; | ||
1172 | break; | ||
1173 | case WLAN_EID_PREP: | ||
1174 | elems->prep = pos; | ||
1175 | elems->prep_len = elen; | ||
1176 | break; | ||
1177 | case WLAN_EID_PERR: | ||
1178 | elems->perr = pos; | ||
1179 | elems->perr_len = elen; | ||
1180 | break; | ||
1181 | case WLAN_EID_RANN: | ||
1182 | if (elen >= sizeof(struct ieee80211_rann_ie)) | ||
1183 | elems->rann = (void *)pos; | ||
1184 | break; | ||
1185 | case WLAN_EID_CHANNEL_SWITCH: | ||
1186 | elems->ch_switch_elem = pos; | ||
1187 | elems->ch_switch_elem_len = elen; | ||
1188 | break; | ||
1189 | case WLAN_EID_QUIET: | ||
1190 | if (!elems->quiet_elem) { | ||
1191 | elems->quiet_elem = pos; | ||
1192 | elems->quiet_elem_len = elen; | ||
1193 | } | ||
1194 | elems->num_of_quiet_elem++; | ||
1195 | break; | ||
1196 | case WLAN_EID_COUNTRY: | ||
1197 | elems->country_elem = pos; | ||
1198 | elems->country_elem_len = elen; | ||
1199 | break; | ||
1200 | case WLAN_EID_PWR_CONSTRAINT: | ||
1201 | elems->pwr_constr_elem = pos; | ||
1202 | elems->pwr_constr_elem_len = elen; | ||
1203 | break; | ||
1204 | case WLAN_EID_TIMEOUT_INTERVAL: | ||
1205 | elems->timeout_int = pos; | ||
1206 | elems->timeout_int_len = elen; | ||
1207 | break; | ||
1208 | default: | ||
1209 | break; | ||
1210 | } | ||
1211 | |||
1212 | left -= elen; | ||
1213 | pos += elen; | ||
1214 | } | ||
1215 | |||
1216 | return crc; | ||
1217 | } | ||
1218 | EXPORT_SYMBOL(ieee802_11_parse_elems_crc); | ||