aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/debugfs_netdev.c
diff options
context:
space:
mode:
authorJouni Malinen <jouni.malinen@atheros.com>2011-02-03 11:35:19 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-02-03 16:45:29 -0500
commit681d119047761cc59a15c0bb86891f3a878997cf (patch)
treeb118fdf78870de7eea5a0449e84b4e11b046b5be /net/mac80211/debugfs_netdev.c
parent747d753df7fea1d2d29c5c33623f6d2e5d0ed2d6 (diff)
mac80211: Add testing functionality for TKIP
TKIP countermeasures depend on devices being able to detect Michael MIC failures on received frames and for stations to report errors to the AP. In order to test that behavior, it is useful to be able to send out TKIP frames with incorrect Michael MIC. This testing behavior has minimal effect on the TX path, so it can be added to mac80211 for convenient use. The interface for using this functionality is a file in mac80211 netdev debugfs (tkip_mic_test). Writing a MAC address to the file makes mac80211 generate a dummy data frame that will be sent out using invalid Michael MIC value. In AP mode, the address needs to be for one of the associated stations or ff:ff:ff:ff:ff:ff to use a broadcast frame. In station mode, the address can be anything, e.g., the current BSSID. It should be noted that this functionality works correctly only when associated and using TKIP. Signed-off-by: Jouni Malinen <jouni.malinen@atheros.com> Acked-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/debugfs_netdev.c')
-rw-r--r--net/mac80211/debugfs_netdev.c102
1 files changed, 101 insertions, 1 deletions
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 4cffbf65cccd..dacace6b1393 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -36,7 +36,7 @@ static ssize_t ieee80211_if_read(
36 ret = (*format)(sdata, buf, sizeof(buf)); 36 ret = (*format)(sdata, buf, sizeof(buf));
37 read_unlock(&dev_base_lock); 37 read_unlock(&dev_base_lock);
38 38
39 if (ret != -EINVAL) 39 if (ret >= 0)
40 ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret); 40 ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
41 41
42 return ret; 42 return ret;
@@ -221,6 +221,104 @@ static ssize_t ieee80211_if_parse_smps(struct ieee80211_sub_if_data *sdata,
221 221
222__IEEE80211_IF_FILE_W(smps); 222__IEEE80211_IF_FILE_W(smps);
223 223
224static ssize_t ieee80211_if_fmt_tkip_mic_test(
225 const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
226{
227 return -EOPNOTSUPP;
228}
229
230static int hwaddr_aton(const char *txt, u8 *addr)
231{
232 int i;
233
234 for (i = 0; i < ETH_ALEN; i++) {
235 int a, b;
236
237 a = hex_to_bin(*txt++);
238 if (a < 0)
239 return -1;
240 b = hex_to_bin(*txt++);
241 if (b < 0)
242 return -1;
243 *addr++ = (a << 4) | b;
244 if (i < 5 && *txt++ != ':')
245 return -1;
246 }
247
248 return 0;
249}
250
251static ssize_t ieee80211_if_parse_tkip_mic_test(
252 struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
253{
254 struct ieee80211_local *local = sdata->local;
255 u8 addr[ETH_ALEN];
256 struct sk_buff *skb;
257 struct ieee80211_hdr *hdr;
258 __le16 fc;
259
260 /*
261 * Assume colon-delimited MAC address with possible white space
262 * following.
263 */
264 if (buflen < 3 * ETH_ALEN - 1)
265 return -EINVAL;
266 if (hwaddr_aton(buf, addr) < 0)
267 return -EINVAL;
268
269 if (!ieee80211_sdata_running(sdata))
270 return -ENOTCONN;
271
272 skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24 + 100);
273 if (!skb)
274 return -ENOMEM;
275 skb_reserve(skb, local->hw.extra_tx_headroom);
276
277 hdr = (struct ieee80211_hdr *) skb_put(skb, 24);
278 memset(hdr, 0, 24);
279 fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
280
281 switch (sdata->vif.type) {
282 case NL80211_IFTYPE_AP:
283 fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
284 /* DA BSSID SA */
285 memcpy(hdr->addr1, addr, ETH_ALEN);
286 memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
287 memcpy(hdr->addr3, sdata->vif.addr, ETH_ALEN);
288 break;
289 case NL80211_IFTYPE_STATION:
290 fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
291 /* BSSID SA DA */
292 if (sdata->vif.bss_conf.bssid == NULL) {
293 dev_kfree_skb(skb);
294 return -ENOTCONN;
295 }
296 memcpy(hdr->addr1, sdata->vif.bss_conf.bssid, ETH_ALEN);
297 memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
298 memcpy(hdr->addr3, addr, ETH_ALEN);
299 break;
300 default:
301 dev_kfree_skb(skb);
302 return -EOPNOTSUPP;
303 }
304 hdr->frame_control = fc;
305
306 /*
307 * Add some length to the test frame to make it look bit more valid.
308 * The exact contents does not matter since the recipient is required
309 * to drop this because of the Michael MIC failure.
310 */
311 memset(skb_put(skb, 50), 0, 50);
312
313 IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_TKIP_MIC_FAILURE;
314
315 ieee80211_tx_skb(sdata, skb);
316
317 return buflen;
318}
319
320__IEEE80211_IF_FILE_W(tkip_mic_test);
321
224/* AP attributes */ 322/* AP attributes */
225IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC); 323IEEE80211_IF_FILE(num_sta_ps, u.ap.num_sta_ps, ATOMIC);
226IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC); 324IEEE80211_IF_FILE(dtim_count, u.ap.dtim_count, DEC);
@@ -299,6 +397,7 @@ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
299 DEBUGFS_ADD(last_beacon); 397 DEBUGFS_ADD(last_beacon);
300 DEBUGFS_ADD(ave_beacon); 398 DEBUGFS_ADD(ave_beacon);
301 DEBUGFS_ADD_MODE(smps, 0600); 399 DEBUGFS_ADD_MODE(smps, 0600);
400 DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
302} 401}
303 402
304static void add_ap_files(struct ieee80211_sub_if_data *sdata) 403static void add_ap_files(struct ieee80211_sub_if_data *sdata)
@@ -313,6 +412,7 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
313 DEBUGFS_ADD(num_sta_ps); 412 DEBUGFS_ADD(num_sta_ps);
314 DEBUGFS_ADD(dtim_count); 413 DEBUGFS_ADD(dtim_count);
315 DEBUGFS_ADD(num_buffered_multicast); 414 DEBUGFS_ADD(num_buffered_multicast);
415 DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
316} 416}
317 417
318static void add_wds_files(struct ieee80211_sub_if_data *sdata) 418static void add_wds_files(struct ieee80211_sub_if_data *sdata)