diff options
author | David S. Miller <davem@davemloft.net> | 2010-02-04 11:58:14 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-04 11:58:14 -0500 |
commit | 10be7eb36b93364b98688831ee7d26f58402bb96 (patch) | |
tree | eb13ae80fcaa8baacd804a721c5a4962a501a2a4 /net | |
parent | 90c30335a70e96b8b8493b7deb15e6b30e6d9fce (diff) | |
parent | 5ffaf8a361b4c9025963959a744f21d8173c7669 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/debugfs_sta.c | 26 | ||||
-rw-r--r-- | net/mac80211/driver-ops.h | 14 | ||||
-rw-r--r-- | net/mac80211/driver-trace.h | 15 | ||||
-rw-r--r-- | net/mac80211/ibss.c | 22 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 1 | ||||
-rw-r--r-- | net/mac80211/iface.c | 6 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 27 | ||||
-rw-r--r-- | net/mac80211/rate.h | 4 | ||||
-rw-r--r-- | net/mac80211/rc80211_pid_algo.c | 8 | ||||
-rw-r--r-- | net/mac80211/rx.c | 45 | ||||
-rw-r--r-- | net/mac80211/scan.c | 4 | ||||
-rw-r--r-- | net/mac80211/status.c | 35 | ||||
-rw-r--r-- | net/mac80211/tkip.c | 23 | ||||
-rw-r--r-- | net/mac80211/tx.c | 50 | ||||
-rw-r--r-- | net/mac80211/wep.c | 17 | ||||
-rw-r--r-- | net/mac80211/work.c | 19 | ||||
-rw-r--r-- | net/mac80211/wpa.c | 57 | ||||
-rw-r--r-- | net/wireless/core.c | 38 | ||||
-rw-r--r-- | net/wireless/core.h | 3 | ||||
-rw-r--r-- | net/wireless/lib80211_crypt_ccmp.c | 2 | ||||
-rw-r--r-- | net/wireless/lib80211_crypt_tkip.c | 23 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 4 | ||||
-rw-r--r-- | net/wireless/reg.c | 161 | ||||
-rw-r--r-- | net/wireless/reg.h | 18 | ||||
-rw-r--r-- | net/wireless/scan.c | 38 | ||||
-rw-r--r-- | net/wireless/sme.c | 40 | ||||
-rw-r--r-- | net/wireless/sysfs.c | 20 | ||||
-rw-r--r-- | net/wireless/util.c | 5 | ||||
-rw-r--r-- | net/wireless/wext-compat.c | 2 |
29 files changed, 503 insertions, 224 deletions
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index 0d4a759ba72c..d92800bb2d2f 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c | |||
@@ -120,36 +120,38 @@ STA_OPS(last_seq_ctrl); | |||
120 | static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, | 120 | static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, |
121 | size_t count, loff_t *ppos) | 121 | size_t count, loff_t *ppos) |
122 | { | 122 | { |
123 | char buf[30 + STA_TID_NUM * 70], *p = buf; | 123 | char buf[64 + STA_TID_NUM * 40], *p = buf; |
124 | int i; | 124 | int i; |
125 | struct sta_info *sta = file->private_data; | 125 | struct sta_info *sta = file->private_data; |
126 | 126 | ||
127 | spin_lock_bh(&sta->lock); | 127 | spin_lock_bh(&sta->lock); |
128 | p += scnprintf(p, sizeof(buf)+buf-p, "next dialog_token is %#02x\n", | 128 | p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n", |
129 | sta->ampdu_mlme.dialog_token_allocator + 1); | 129 | sta->ampdu_mlme.dialog_token_allocator + 1); |
130 | p += scnprintf(p, sizeof(buf) + buf - p, | ||
131 | "TID\t\tRX\tDTKN\tSSN\t\tTX\tDTKN\tSSN\tpending\n"); | ||
130 | for (i = 0; i < STA_TID_NUM; i++) { | 132 | for (i = 0; i < STA_TID_NUM; i++) { |
131 | p += scnprintf(p, sizeof(buf)+buf-p, "TID %02d:", i); | 133 | p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i); |
132 | p += scnprintf(p, sizeof(buf)+buf-p, " RX=%x", | 134 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", |
133 | sta->ampdu_mlme.tid_state_rx[i]); | 135 | sta->ampdu_mlme.tid_state_rx[i]); |
134 | p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x", | 136 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", |
135 | sta->ampdu_mlme.tid_state_rx[i] ? | 137 | sta->ampdu_mlme.tid_state_rx[i] ? |
136 | sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); | 138 | sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); |
137 | p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x", | 139 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", |
138 | sta->ampdu_mlme.tid_state_rx[i] ? | 140 | sta->ampdu_mlme.tid_state_rx[i] ? |
139 | sta->ampdu_mlme.tid_rx[i]->ssn : 0); | 141 | sta->ampdu_mlme.tid_rx[i]->ssn : 0); |
140 | 142 | ||
141 | p += scnprintf(p, sizeof(buf)+buf-p, " TX=%x", | 143 | p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", |
142 | sta->ampdu_mlme.tid_state_tx[i]); | 144 | sta->ampdu_mlme.tid_state_tx[i]); |
143 | p += scnprintf(p, sizeof(buf)+buf-p, "/DTKN=%#.2x", | 145 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x", |
144 | sta->ampdu_mlme.tid_state_tx[i] ? | 146 | sta->ampdu_mlme.tid_state_tx[i] ? |
145 | sta->ampdu_mlme.tid_tx[i]->dialog_token : 0); | 147 | sta->ampdu_mlme.tid_tx[i]->dialog_token : 0); |
146 | p += scnprintf(p, sizeof(buf)+buf-p, "/SSN=%#.3x", | 148 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x", |
147 | sta->ampdu_mlme.tid_state_tx[i] ? | 149 | sta->ampdu_mlme.tid_state_tx[i] ? |
148 | sta->ampdu_mlme.tid_tx[i]->ssn : 0); | 150 | sta->ampdu_mlme.tid_tx[i]->ssn : 0); |
149 | p += scnprintf(p, sizeof(buf)+buf-p, "/pending=%03d", | 151 | p += scnprintf(p, sizeof(buf) + buf - p, "\t%03d", |
150 | sta->ampdu_mlme.tid_state_tx[i] ? | 152 | sta->ampdu_mlme.tid_state_tx[i] ? |
151 | skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0); | 153 | skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0); |
152 | p += scnprintf(p, sizeof(buf)+buf-p, "\n"); | 154 | p += scnprintf(p, sizeof(buf) + buf - p, "\n"); |
153 | } | 155 | } |
154 | spin_unlock_bh(&sta->lock); | 156 | spin_unlock_bh(&sta->lock); |
155 | 157 | ||
@@ -165,7 +167,7 @@ static ssize_t sta_ht_capa_read(struct file *file, char __user *userbuf, | |||
165 | if (_cond) \ | 167 | if (_cond) \ |
166 | p += scnprintf(p, sizeof(buf)+buf-p, "\t" _str "\n"); \ | 168 | p += scnprintf(p, sizeof(buf)+buf-p, "\t" _str "\n"); \ |
167 | } while (0) | 169 | } while (0) |
168 | char buf[1024], *p = buf; | 170 | char buf[512], *p = buf; |
169 | int i; | 171 | int i; |
170 | struct sta_info *sta = file->private_data; | 172 | struct sta_info *sta = file->private_data; |
171 | struct ieee80211_sta_ht_cap *htc = &sta->sta.ht_cap; | 173 | struct ieee80211_sta_ht_cap *htc = &sta->sta.ht_cap; |
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index de91d39e0276..6c31f38ac7f5 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -137,16 +137,20 @@ static inline int drv_set_key(struct ieee80211_local *local, | |||
137 | } | 137 | } |
138 | 138 | ||
139 | static inline void drv_update_tkip_key(struct ieee80211_local *local, | 139 | static inline void drv_update_tkip_key(struct ieee80211_local *local, |
140 | struct ieee80211_sub_if_data *sdata, | ||
140 | struct ieee80211_key_conf *conf, | 141 | struct ieee80211_key_conf *conf, |
141 | const u8 *address, u32 iv32, | 142 | struct sta_info *sta, u32 iv32, |
142 | u16 *phase1key) | 143 | u16 *phase1key) |
143 | { | 144 | { |
144 | might_sleep(); | 145 | struct ieee80211_sta *ista = NULL; |
146 | |||
147 | if (sta) | ||
148 | ista = &sta->sta; | ||
145 | 149 | ||
146 | if (local->ops->update_tkip_key) | 150 | if (local->ops->update_tkip_key) |
147 | local->ops->update_tkip_key(&local->hw, conf, address, | 151 | local->ops->update_tkip_key(&local->hw, &sdata->vif, conf, |
148 | iv32, phase1key); | 152 | ista, iv32, phase1key); |
149 | trace_drv_update_tkip_key(local, conf, address, iv32); | 153 | trace_drv_update_tkip_key(local, sdata, conf, ista, iv32); |
150 | } | 154 | } |
151 | 155 | ||
152 | static inline int drv_hw_scan(struct ieee80211_local *local, | 156 | static inline int drv_hw_scan(struct ieee80211_local *local, |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index d6bd9f517401..502424b2538a 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -331,26 +331,29 @@ TRACE_EVENT(drv_set_key, | |||
331 | 331 | ||
332 | TRACE_EVENT(drv_update_tkip_key, | 332 | TRACE_EVENT(drv_update_tkip_key, |
333 | TP_PROTO(struct ieee80211_local *local, | 333 | TP_PROTO(struct ieee80211_local *local, |
334 | struct ieee80211_sub_if_data *sdata, | ||
334 | struct ieee80211_key_conf *conf, | 335 | struct ieee80211_key_conf *conf, |
335 | const u8 *address, u32 iv32), | 336 | struct ieee80211_sta *sta, u32 iv32), |
336 | 337 | ||
337 | TP_ARGS(local, conf, address, iv32), | 338 | TP_ARGS(local, sdata, conf, sta, iv32), |
338 | 339 | ||
339 | TP_STRUCT__entry( | 340 | TP_STRUCT__entry( |
340 | LOCAL_ENTRY | 341 | LOCAL_ENTRY |
341 | __array(u8, addr, 6) | 342 | VIF_ENTRY |
343 | STA_ENTRY | ||
342 | __field(u32, iv32) | 344 | __field(u32, iv32) |
343 | ), | 345 | ), |
344 | 346 | ||
345 | TP_fast_assign( | 347 | TP_fast_assign( |
346 | LOCAL_ASSIGN; | 348 | LOCAL_ASSIGN; |
347 | memcpy(__entry->addr, address, 6); | 349 | VIF_ASSIGN; |
350 | STA_ASSIGN; | ||
348 | __entry->iv32 = iv32; | 351 | __entry->iv32 = iv32; |
349 | ), | 352 | ), |
350 | 353 | ||
351 | TP_printk( | 354 | TP_printk( |
352 | LOCAL_PR_FMT " addr:%pM iv32:%#x", | 355 | LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " iv32:%#x", |
353 | LOCAL_PR_ARG, __entry->addr, __entry->iv32 | 356 | LOCAL_PR_ARG,VIF_PR_ARG,STA_PR_ARG, __entry->iv32 |
354 | ) | 357 | ) |
355 | ); | 358 | ); |
356 | 359 | ||
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 5bcde4c3fba1..f95750b423e3 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c | |||
@@ -293,12 +293,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
293 | 293 | ||
294 | /* check if we need to merge IBSS */ | 294 | /* check if we need to merge IBSS */ |
295 | 295 | ||
296 | /* merge only on beacons (???) */ | ||
297 | if (!beacon) | ||
298 | goto put_bss; | ||
299 | |||
300 | /* we use a fixed BSSID */ | 296 | /* we use a fixed BSSID */ |
301 | if (sdata->u.ibss.bssid) | 297 | if (sdata->u.ibss.fixed_bssid) |
302 | goto put_bss; | 298 | goto put_bss; |
303 | 299 | ||
304 | /* not an IBSS */ | 300 | /* not an IBSS */ |
@@ -454,6 +450,9 @@ static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata) | |||
454 | return active; | 450 | return active; |
455 | } | 451 | } |
456 | 452 | ||
453 | /* | ||
454 | * This function is called with state == IEEE80211_IBSS_MLME_JOINED | ||
455 | */ | ||
457 | 456 | ||
458 | static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) | 457 | static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) |
459 | { | 458 | { |
@@ -519,6 +518,10 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) | |||
519 | capability, 0); | 518 | capability, 0); |
520 | } | 519 | } |
521 | 520 | ||
521 | /* | ||
522 | * This function is called with state == IEEE80211_IBSS_MLME_SEARCH | ||
523 | */ | ||
524 | |||
522 | static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | 525 | static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) |
523 | { | 526 | { |
524 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; | 527 | struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; |
@@ -575,18 +578,14 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
575 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ | 578 | #endif /* CONFIG_MAC80211_IBSS_DEBUG */ |
576 | 579 | ||
577 | /* Selected IBSS not found in current scan results - try to scan */ | 580 | /* Selected IBSS not found in current scan results - try to scan */ |
578 | if (ifibss->state == IEEE80211_IBSS_MLME_JOINED && | 581 | if (time_after(jiffies, ifibss->last_scan_completed + |
579 | !ieee80211_sta_active_ibss(sdata)) { | ||
580 | mod_timer(&ifibss->timer, | ||
581 | round_jiffies(jiffies + IEEE80211_IBSS_MERGE_INTERVAL)); | ||
582 | } else if (time_after(jiffies, ifibss->last_scan_completed + | ||
583 | IEEE80211_SCAN_INTERVAL)) { | 582 | IEEE80211_SCAN_INTERVAL)) { |
584 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " | 583 | printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to " |
585 | "join\n", sdata->name); | 584 | "join\n", sdata->name); |
586 | 585 | ||
587 | ieee80211_request_internal_scan(sdata, ifibss->ssid, | 586 | ieee80211_request_internal_scan(sdata, ifibss->ssid, |
588 | ifibss->ssid_len); | 587 | ifibss->ssid_len); |
589 | } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) { | 588 | } else { |
590 | int interval = IEEE80211_SCAN_INTERVAL; | 589 | int interval = IEEE80211_SCAN_INTERVAL; |
591 | 590 | ||
592 | if (time_after(jiffies, ifibss->ibss_join_req + | 591 | if (time_after(jiffies, ifibss->ibss_join_req + |
@@ -604,7 +603,6 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) | |||
604 | interval = IEEE80211_SCAN_INTERVAL_SLOW; | 603 | interval = IEEE80211_SCAN_INTERVAL_SLOW; |
605 | } | 604 | } |
606 | 605 | ||
607 | ifibss->state = IEEE80211_IBSS_MLME_SEARCH; | ||
608 | mod_timer(&ifibss->timer, | 606 | mod_timer(&ifibss->timer, |
609 | round_jiffies(jiffies + interval)); | 607 | round_jiffies(jiffies + interval)); |
610 | } | 608 | } |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index c18f576f1848..3067fbd69d63 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -299,7 +299,6 @@ struct ieee80211_work { | |||
299 | } assoc; | 299 | } assoc; |
300 | struct { | 300 | struct { |
301 | u32 duration; | 301 | u32 duration; |
302 | bool started; | ||
303 | } remain; | 302 | } remain; |
304 | }; | 303 | }; |
305 | 304 | ||
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index edf21cebeee8..09fff4662e80 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -695,10 +695,14 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev, | |||
695 | 695 | ||
696 | hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len)); | 696 | hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len)); |
697 | 697 | ||
698 | if (!ieee80211_is_data_qos(hdr->frame_control)) { | 698 | if (!ieee80211_is_data(hdr->frame_control)) { |
699 | skb->priority = 7; | 699 | skb->priority = 7; |
700 | return ieee802_1d_to_ac[skb->priority]; | 700 | return ieee802_1d_to_ac[skb->priority]; |
701 | } | 701 | } |
702 | if (!ieee80211_is_data_qos(hdr->frame_control)) { | ||
703 | skb->priority = 0; | ||
704 | return ieee802_1d_to_ac[skb->priority]; | ||
705 | } | ||
702 | 706 | ||
703 | p = ieee80211_get_qos_ctl(hdr); | 707 | p = ieee80211_get_qos_ctl(hdr); |
704 | skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; | 708 | skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; |
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 1e1d16c55ee5..86c6ad1b058d 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -484,6 +484,7 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
484 | 484 | ||
485 | if (count == 1 && found->u.mgd.powersave && | 485 | if (count == 1 && found->u.mgd.powersave && |
486 | found->u.mgd.associated && | 486 | found->u.mgd.associated && |
487 | found->u.mgd.associated->beacon_ies && | ||
487 | !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | | 488 | !(found->u.mgd.flags & (IEEE80211_STA_BEACON_POLL | |
488 | IEEE80211_STA_CONNECTION_POLL))) { | 489 | IEEE80211_STA_CONNECTION_POLL))) { |
489 | s32 beaconint_us; | 490 | s32 beaconint_us; |
@@ -497,14 +498,22 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency) | |||
497 | if (beaconint_us > latency) { | 498 | if (beaconint_us > latency) { |
498 | local->ps_sdata = NULL; | 499 | local->ps_sdata = NULL; |
499 | } else { | 500 | } else { |
500 | u8 dtimper = found->vif.bss_conf.dtim_period; | 501 | struct ieee80211_bss *bss; |
501 | int maxslp = 1; | 502 | int maxslp = 1; |
503 | u8 dtimper; | ||
502 | 504 | ||
503 | if (dtimper > 1) | 505 | bss = (void *)found->u.mgd.associated->priv; |
506 | dtimper = bss->dtim_period; | ||
507 | |||
508 | /* If the TIM IE is invalid, pretend the value is 1 */ | ||
509 | if (!dtimper) | ||
510 | dtimper = 1; | ||
511 | else if (dtimper > 1) | ||
504 | maxslp = min_t(int, dtimper, | 512 | maxslp = min_t(int, dtimper, |
505 | latency / beaconint_us); | 513 | latency / beaconint_us); |
506 | 514 | ||
507 | local->hw.conf.max_sleep_period = maxslp; | 515 | local->hw.conf.max_sleep_period = maxslp; |
516 | local->hw.conf.ps_dtim_period = dtimper; | ||
508 | local->ps_sdata = found; | 517 | local->ps_sdata = found; |
509 | } | 518 | } |
510 | } else { | 519 | } else { |
@@ -702,7 +711,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, | |||
702 | /* set timing information */ | 711 | /* set timing information */ |
703 | sdata->vif.bss_conf.beacon_int = cbss->beacon_interval; | 712 | sdata->vif.bss_conf.beacon_int = cbss->beacon_interval; |
704 | sdata->vif.bss_conf.timestamp = cbss->tsf; | 713 | sdata->vif.bss_conf.timestamp = cbss->tsf; |
705 | sdata->vif.bss_conf.dtim_period = bss->dtim_period; | ||
706 | 714 | ||
707 | bss_info_changed |= BSS_CHANGED_BEACON_INT; | 715 | bss_info_changed |= BSS_CHANGED_BEACON_INT; |
708 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, | 716 | bss_info_changed |= ieee80211_handle_bss_capability(sdata, |
@@ -1168,6 +1176,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1168 | int freq; | 1176 | int freq; |
1169 | struct ieee80211_bss *bss; | 1177 | struct ieee80211_bss *bss; |
1170 | struct ieee80211_channel *channel; | 1178 | struct ieee80211_channel *channel; |
1179 | bool need_ps = false; | ||
1180 | |||
1181 | if (sdata->u.mgd.associated) { | ||
1182 | bss = (void *)sdata->u.mgd.associated->priv; | ||
1183 | /* not previously set so we may need to recalc */ | ||
1184 | need_ps = !bss->dtim_period; | ||
1185 | } | ||
1171 | 1186 | ||
1172 | if (elems->ds_params && elems->ds_params_len == 1) | 1187 | if (elems->ds_params && elems->ds_params_len == 1) |
1173 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); | 1188 | freq = ieee80211_channel_to_frequency(elems->ds_params[0]); |
@@ -1187,6 +1202,12 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1187 | if (!sdata->u.mgd.associated) | 1202 | if (!sdata->u.mgd.associated) |
1188 | return; | 1203 | return; |
1189 | 1204 | ||
1205 | if (need_ps) { | ||
1206 | mutex_lock(&local->iflist_mtx); | ||
1207 | ieee80211_recalc_ps(local, -1); | ||
1208 | mutex_unlock(&local->iflist_mtx); | ||
1209 | } | ||
1210 | |||
1190 | if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && | 1211 | if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) && |
1191 | (memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, | 1212 | (memcmp(mgmt->bssid, sdata->u.mgd.associated->bssid, |
1192 | ETH_ALEN) == 0)) { | 1213 | ETH_ALEN) == 0)) { |
diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 669dddd40521..998cf7a935b6 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h | |||
@@ -44,6 +44,10 @@ static inline void rate_control_tx_status(struct ieee80211_local *local, | |||
44 | struct rate_control_ref *ref = local->rate_ctrl; | 44 | struct rate_control_ref *ref = local->rate_ctrl; |
45 | struct ieee80211_sta *ista = &sta->sta; | 45 | struct ieee80211_sta *ista = &sta->sta; |
46 | void *priv_sta = sta->rate_ctrl_priv; | 46 | void *priv_sta = sta->rate_ctrl_priv; |
47 | |||
48 | if (!ref) | ||
49 | return; | ||
50 | |||
47 | ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); | 51 | ref->ops->tx_status(ref->priv, sband, ista, priv_sta, skb); |
48 | } | 52 | } |
49 | 53 | ||
diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 29bc4c516238..2652a374974e 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c | |||
@@ -157,9 +157,7 @@ static void rate_control_pid_sample(struct rc_pid_info *pinfo, | |||
157 | 157 | ||
158 | /* In case nothing happened during the previous control interval, turn | 158 | /* In case nothing happened during the previous control interval, turn |
159 | * the sharpening factor on. */ | 159 | * the sharpening factor on. */ |
160 | period = (HZ * pinfo->sampling_period + 500) / 1000; | 160 | period = msecs_to_jiffies(pinfo->sampling_period); |
161 | if (!period) | ||
162 | period = 1; | ||
163 | if (jiffies - spinfo->last_sample > 2 * period) | 161 | if (jiffies - spinfo->last_sample > 2 * period) |
164 | spinfo->sharp_cnt = pinfo->sharpen_duration; | 162 | spinfo->sharp_cnt = pinfo->sharpen_duration; |
165 | 163 | ||
@@ -252,9 +250,7 @@ static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_ba | |||
252 | } | 250 | } |
253 | 251 | ||
254 | /* Update PID controller state. */ | 252 | /* Update PID controller state. */ |
255 | period = (HZ * pinfo->sampling_period + 500) / 1000; | 253 | period = msecs_to_jiffies(pinfo->sampling_period); |
256 | if (!period) | ||
257 | period = 1; | ||
258 | if (time_after(jiffies, spinfo->last_sample + period)) | 254 | if (time_after(jiffies, spinfo->last_sample + period)) |
259 | rate_control_pid_sample(pinfo, sband, sta, spinfo); | 255 | rate_control_pid_sample(pinfo, sband, sta, spinfo); |
260 | } | 256 | } |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index a8e15b84c05b..5709307fcb9b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -2348,22 +2348,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
2348 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) | 2348 | sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
2349 | continue; | 2349 | continue; |
2350 | 2350 | ||
2351 | rx.sta = sta_info_get(sdata, hdr->addr2); | ||
2352 | |||
2353 | rx.flags |= IEEE80211_RX_RA_MATCH; | ||
2354 | prepares = prepare_for_handlers(sdata, &rx, hdr); | ||
2355 | |||
2356 | if (!prepares) | ||
2357 | continue; | ||
2358 | |||
2359 | if (status->flag & RX_FLAG_MMIC_ERROR) { | ||
2360 | rx.sdata = sdata; | ||
2361 | if (rx.flags & IEEE80211_RX_RA_MATCH) | ||
2362 | ieee80211_rx_michael_mic_report(hdr, | ||
2363 | &rx); | ||
2364 | continue; | ||
2365 | } | ||
2366 | |||
2367 | /* | 2351 | /* |
2368 | * frame is destined for this interface, but if it's | 2352 | * frame is destined for this interface, but if it's |
2369 | * not also for the previous one we handle that after | 2353 | * not also for the previous one we handle that after |
@@ -2375,6 +2359,22 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
2375 | continue; | 2359 | continue; |
2376 | } | 2360 | } |
2377 | 2361 | ||
2362 | rx.sta = sta_info_get_bss(prev, hdr->addr2); | ||
2363 | |||
2364 | rx.flags |= IEEE80211_RX_RA_MATCH; | ||
2365 | prepares = prepare_for_handlers(prev, &rx, hdr); | ||
2366 | |||
2367 | if (!prepares) | ||
2368 | goto next; | ||
2369 | |||
2370 | if (status->flag & RX_FLAG_MMIC_ERROR) { | ||
2371 | rx.sdata = prev; | ||
2372 | if (rx.flags & IEEE80211_RX_RA_MATCH) | ||
2373 | ieee80211_rx_michael_mic_report(hdr, | ||
2374 | &rx); | ||
2375 | goto next; | ||
2376 | } | ||
2377 | |||
2378 | /* | 2378 | /* |
2379 | * frame was destined for the previous interface | 2379 | * frame was destined for the previous interface |
2380 | * so invoke RX handlers for it | 2380 | * so invoke RX handlers for it |
@@ -2387,11 +2387,22 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, | |||
2387 | "multicast frame for %s\n", | 2387 | "multicast frame for %s\n", |
2388 | wiphy_name(local->hw.wiphy), | 2388 | wiphy_name(local->hw.wiphy), |
2389 | prev->name); | 2389 | prev->name); |
2390 | continue; | 2390 | goto next; |
2391 | } | 2391 | } |
2392 | ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate); | 2392 | ieee80211_invoke_rx_handlers(prev, &rx, skb_new, rate); |
2393 | next: | ||
2393 | prev = sdata; | 2394 | prev = sdata; |
2394 | } | 2395 | } |
2396 | |||
2397 | if (prev) { | ||
2398 | rx.sta = sta_info_get_bss(prev, hdr->addr2); | ||
2399 | |||
2400 | rx.flags |= IEEE80211_RX_RA_MATCH; | ||
2401 | prepares = prepare_for_handlers(prev, &rx, hdr); | ||
2402 | |||
2403 | if (!prepares) | ||
2404 | prev = NULL; | ||
2405 | } | ||
2395 | } | 2406 | } |
2396 | if (prev) | 2407 | if (prev) |
2397 | ieee80211_invoke_rx_handlers(prev, &rx, skb, rate); | 2408 | ieee80211_invoke_rx_handlers(prev, &rx, skb, rate); |
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 9afe2f9885dc..bc061f629674 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c | |||
@@ -111,10 +111,6 @@ ieee80211_bss_info_update(struct ieee80211_local *local, | |||
111 | bss->dtim_period = tim_ie->dtim_period; | 111 | bss->dtim_period = tim_ie->dtim_period; |
112 | } | 112 | } |
113 | 113 | ||
114 | /* set default value for buggy AP/no TIM element */ | ||
115 | if (bss->dtim_period == 0) | ||
116 | bss->dtim_period = 1; | ||
117 | |||
118 | bss->supp_rates_len = 0; | 114 | bss->supp_rates_len = 0; |
119 | if (elems->supp_rates) { | 115 | if (elems->supp_rates) { |
120 | clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; | 116 | clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len; |
diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 0ebcdda24200..e57ad6b1d7ea 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c | |||
@@ -45,29 +45,19 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
45 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 45 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
46 | 46 | ||
47 | /* | 47 | /* |
48 | * XXX: This is temporary! | 48 | * This skb 'survived' a round-trip through the driver, and |
49 | * | 49 | * hopefully the driver didn't mangle it too badly. However, |
50 | * The problem here is that when we get here, the driver will | 50 | * we can definitely not rely on the the control information |
51 | * quite likely have pretty much overwritten info->control by | 51 | * being correct. Clear it so we don't get junk there, and |
52 | * using info->driver_data or info->rate_driver_data. Thus, | 52 | * indicate that it needs new processing, but must not be |
53 | * when passing out the frame to the driver again, we would be | 53 | * modified/encrypted again. |
54 | * passing completely bogus data since the driver would then | ||
55 | * expect a properly filled info->control. In mac80211 itself | ||
56 | * the same problem occurs, since we need info->control.vif | ||
57 | * internally. | ||
58 | * | ||
59 | * To fix this, we should send the frame through TX processing | ||
60 | * again. However, it's not that simple, since the frame will | ||
61 | * have been software-encrypted (if applicable) already, and | ||
62 | * encrypting it again doesn't do much good. So to properly do | ||
63 | * that, we not only have to skip the actual 'raw' encryption | ||
64 | * (key selection etc. still has to be done!) but also the | ||
65 | * sequence number assignment since that impacts the crypto | ||
66 | * encapsulation, of course. | ||
67 | * | ||
68 | * Hence, for now, fix the bug by just dropping the frame. | ||
69 | */ | 54 | */ |
70 | goto drop; | 55 | memset(&info->control, 0, sizeof(info->control)); |
56 | |||
57 | info->control.jiffies = jiffies; | ||
58 | info->control.vif = &sta->sdata->vif; | ||
59 | info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING | | ||
60 | IEEE80211_TX_INTFL_RETRANSMISSION; | ||
71 | 61 | ||
72 | sta->tx_filtered_count++; | 62 | sta->tx_filtered_count++; |
73 | 63 | ||
@@ -122,7 +112,6 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, | |||
122 | return; | 112 | return; |
123 | } | 113 | } |
124 | 114 | ||
125 | drop: | ||
126 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG | 115 | #ifdef CONFIG_MAC80211_VERBOSE_DEBUG |
127 | if (net_ratelimit()) | 116 | if (net_ratelimit()) |
128 | printk(KERN_DEBUG "%s: dropped TX filtered frame, " | 117 | printk(KERN_DEBUG "%s: dropped TX filtered frame, " |
diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index b73454a507f9..7ef491e9d66d 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c | |||
@@ -195,11 +195,13 @@ void ieee80211_get_tkip_key(struct ieee80211_key_conf *keyconf, | |||
195 | } | 195 | } |
196 | EXPORT_SYMBOL(ieee80211_get_tkip_key); | 196 | EXPORT_SYMBOL(ieee80211_get_tkip_key); |
197 | 197 | ||
198 | /* Encrypt packet payload with TKIP using @key. @pos is a pointer to the | 198 | /* |
199 | * Encrypt packet payload with TKIP using @key. @pos is a pointer to the | ||
199 | * beginning of the buffer containing payload. This payload must include | 200 | * beginning of the buffer containing payload. This payload must include |
200 | * headroom of eight octets for IV and Ext. IV and taildroom of four octets | 201 | * the IV/Ext.IV and space for (taildroom) four octets for ICV. |
201 | * for ICV. @payload_len is the length of payload (_not_ including extra | 202 | * @payload_len is the length of payload (_not_ including IV/ICV length). |
202 | * headroom and tailroom). @ta is the transmitter addresses. */ | 203 | * @ta is the transmitter addresses. |
204 | */ | ||
203 | void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, | 205 | void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, |
204 | struct ieee80211_key *key, | 206 | struct ieee80211_key *key, |
205 | u8 *pos, size_t payload_len, u8 *ta) | 207 | u8 *pos, size_t payload_len, u8 *ta) |
@@ -214,7 +216,6 @@ void ieee80211_tkip_encrypt_data(struct crypto_blkcipher *tfm, | |||
214 | 216 | ||
215 | tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key); | 217 | tkip_mixing_phase2(tk, ctx, ctx->iv16, rc4key); |
216 | 218 | ||
217 | pos = ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16); | ||
218 | ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len); | 219 | ieee80211_wep_encrypt_data(tfm, rc4key, 16, pos, payload_len); |
219 | } | 220 | } |
220 | 221 | ||
@@ -303,14 +304,12 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, | |||
303 | if (key->local->ops->update_tkip_key && | 304 | if (key->local->ops->update_tkip_key && |
304 | key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && | 305 | key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && |
305 | key->u.tkip.rx[queue].state != TKIP_STATE_PHASE1_HW_UPLOADED) { | 306 | key->u.tkip.rx[queue].state != TKIP_STATE_PHASE1_HW_UPLOADED) { |
306 | static const u8 bcast[ETH_ALEN] = | 307 | struct ieee80211_sub_if_data *sdata = key->sdata; |
307 | {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | ||
308 | const u8 *sta_addr = key->sta->sta.addr; | ||
309 | |||
310 | if (is_multicast_ether_addr(ra)) | ||
311 | sta_addr = bcast; | ||
312 | 308 | ||
313 | drv_update_tkip_key(key->local, &key->conf, sta_addr, | 309 | if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) |
310 | sdata = container_of(key->sdata->bss, | ||
311 | struct ieee80211_sub_if_data, u.ap); | ||
312 | drv_update_tkip_key(key->local, sdata, &key->conf, key->sta, | ||
314 | iv32, key->u.tkip.rx[queue].p1k); | 313 | iv32, key->u.tkip.rx[queue].p1k); |
315 | key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED; | 314 | key->u.tkip.rx[queue].state = TKIP_STATE_PHASE1_HW_UPLOADED; |
316 | } | 315 | } |
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index daf81048c1f7..85e382aa894e 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c | |||
@@ -529,6 +529,8 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
529 | tx->key = NULL; | 529 | tx->key = NULL; |
530 | 530 | ||
531 | if (tx->key) { | 531 | if (tx->key) { |
532 | bool skip_hw = false; | ||
533 | |||
532 | tx->key->tx_rx_count++; | 534 | tx->key->tx_rx_count++; |
533 | /* TODO: add threshold stuff again */ | 535 | /* TODO: add threshold stuff again */ |
534 | 536 | ||
@@ -545,16 +547,32 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) | |||
545 | !ieee80211_use_mfp(hdr->frame_control, tx->sta, | 547 | !ieee80211_use_mfp(hdr->frame_control, tx->sta, |
546 | tx->skb)) | 548 | tx->skb)) |
547 | tx->key = NULL; | 549 | tx->key = NULL; |
550 | else | ||
551 | skip_hw = (tx->key->conf.flags & | ||
552 | IEEE80211_KEY_FLAG_SW_MGMT) && | ||
553 | ieee80211_is_mgmt(hdr->frame_control); | ||
548 | break; | 554 | break; |
549 | case ALG_AES_CMAC: | 555 | case ALG_AES_CMAC: |
550 | if (!ieee80211_is_mgmt(hdr->frame_control)) | 556 | if (!ieee80211_is_mgmt(hdr->frame_control)) |
551 | tx->key = NULL; | 557 | tx->key = NULL; |
552 | break; | 558 | break; |
553 | } | 559 | } |
560 | |||
561 | if (!skip_hw && tx->key && | ||
562 | tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) | ||
563 | info->control.hw_key = &tx->key->conf; | ||
554 | } | 564 | } |
555 | 565 | ||
556 | if (!tx->key || !(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) | 566 | return TX_CONTINUE; |
557 | info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; | 567 | } |
568 | |||
569 | static ieee80211_tx_result debug_noinline | ||
570 | ieee80211_tx_h_sta(struct ieee80211_tx_data *tx) | ||
571 | { | ||
572 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | ||
573 | |||
574 | if (tx->sta) | ||
575 | info->control.sta = &tx->sta->sta; | ||
558 | 576 | ||
559 | return TX_CONTINUE; | 577 | return TX_CONTINUE; |
560 | } | 578 | } |
@@ -734,17 +752,6 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) | |||
734 | } | 752 | } |
735 | 753 | ||
736 | static ieee80211_tx_result debug_noinline | 754 | static ieee80211_tx_result debug_noinline |
737 | ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) | ||
738 | { | ||
739 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | ||
740 | |||
741 | if (tx->sta) | ||
742 | info->control.sta = &tx->sta->sta; | ||
743 | |||
744 | return TX_CONTINUE; | ||
745 | } | ||
746 | |||
747 | static ieee80211_tx_result debug_noinline | ||
748 | ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) | 755 | ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) |
749 | { | 756 | { |
750 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); | 757 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); |
@@ -1101,7 +1108,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1101 | tx->flags |= IEEE80211_TX_FRAGMENTED; | 1108 | tx->flags |= IEEE80211_TX_FRAGMENTED; |
1102 | 1109 | ||
1103 | /* process and remove the injection radiotap header */ | 1110 | /* process and remove the injection radiotap header */ |
1104 | if (unlikely(info->flags & IEEE80211_TX_CTL_INJECTED)) { | 1111 | if (unlikely(info->flags & IEEE80211_TX_INTFL_HAS_RADIOTAP)) { |
1105 | if (!__ieee80211_parse_tx_radiotap(tx, skb)) | 1112 | if (!__ieee80211_parse_tx_radiotap(tx, skb)) |
1106 | return TX_DROP; | 1113 | return TX_DROP; |
1107 | 1114 | ||
@@ -1110,6 +1117,7 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1110 | * the radiotap header that was present and pre-filled | 1117 | * the radiotap header that was present and pre-filled |
1111 | * 'tx' with tx control information. | 1118 | * 'tx' with tx control information. |
1112 | */ | 1119 | */ |
1120 | info->flags &= ~IEEE80211_TX_INTFL_HAS_RADIOTAP; | ||
1113 | } | 1121 | } |
1114 | 1122 | ||
1115 | /* | 1123 | /* |
@@ -1125,6 +1133,8 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata, | |||
1125 | tx->sta = rcu_dereference(sdata->u.vlan.sta); | 1133 | tx->sta = rcu_dereference(sdata->u.vlan.sta); |
1126 | if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr) | 1134 | if (!tx->sta && sdata->dev->ieee80211_ptr->use_4addr) |
1127 | return TX_DROP; | 1135 | return TX_DROP; |
1136 | } else if (info->flags & IEEE80211_TX_CTL_INJECTED) { | ||
1137 | tx->sta = sta_info_get_bss(sdata, hdr->addr1); | ||
1128 | } | 1138 | } |
1129 | if (!tx->sta) | 1139 | if (!tx->sta) |
1130 | tx->sta = sta_info_get(sdata, hdr->addr1); | 1140 | tx->sta = sta_info_get(sdata, hdr->addr1); |
@@ -1279,6 +1289,7 @@ static int __ieee80211_tx(struct ieee80211_local *local, | |||
1279 | static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | 1289 | static int invoke_tx_handlers(struct ieee80211_tx_data *tx) |
1280 | { | 1290 | { |
1281 | struct sk_buff *skb = tx->skb; | 1291 | struct sk_buff *skb = tx->skb; |
1292 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
1282 | ieee80211_tx_result res = TX_DROP; | 1293 | ieee80211_tx_result res = TX_DROP; |
1283 | 1294 | ||
1284 | #define CALL_TXH(txh) \ | 1295 | #define CALL_TXH(txh) \ |
@@ -1292,10 +1303,14 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx) | |||
1292 | CALL_TXH(ieee80211_tx_h_check_assoc); | 1303 | CALL_TXH(ieee80211_tx_h_check_assoc); |
1293 | CALL_TXH(ieee80211_tx_h_ps_buf); | 1304 | CALL_TXH(ieee80211_tx_h_ps_buf); |
1294 | CALL_TXH(ieee80211_tx_h_select_key); | 1305 | CALL_TXH(ieee80211_tx_h_select_key); |
1295 | CALL_TXH(ieee80211_tx_h_michael_mic_add); | 1306 | CALL_TXH(ieee80211_tx_h_sta); |
1296 | if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)) | 1307 | if (!(tx->local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)) |
1297 | CALL_TXH(ieee80211_tx_h_rate_ctrl); | 1308 | CALL_TXH(ieee80211_tx_h_rate_ctrl); |
1298 | CALL_TXH(ieee80211_tx_h_misc); | 1309 | |
1310 | if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) | ||
1311 | goto txh_done; | ||
1312 | |||
1313 | CALL_TXH(ieee80211_tx_h_michael_mic_add); | ||
1299 | CALL_TXH(ieee80211_tx_h_sequence); | 1314 | CALL_TXH(ieee80211_tx_h_sequence); |
1300 | CALL_TXH(ieee80211_tx_h_fragment); | 1315 | CALL_TXH(ieee80211_tx_h_fragment); |
1301 | /* handlers after fragment must be aware of tx info fragmentation! */ | 1316 | /* handlers after fragment must be aware of tx info fragmentation! */ |
@@ -1487,7 +1502,8 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, | |||
1487 | int hdrlen; | 1502 | int hdrlen; |
1488 | u16 len_rthdr; | 1503 | u16 len_rthdr; |
1489 | 1504 | ||
1490 | info->flags |= IEEE80211_TX_CTL_INJECTED; | 1505 | info->flags |= IEEE80211_TX_CTL_INJECTED | |
1506 | IEEE80211_TX_INTFL_HAS_RADIOTAP; | ||
1491 | 1507 | ||
1492 | len_rthdr = ieee80211_get_radiotap_len(skb->data); | 1508 | len_rthdr = ieee80211_get_radiotap_len(skb->data); |
1493 | hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); | 1509 | hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr); |
diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 247123fe1a7a..5d745f2d7236 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c | |||
@@ -305,20 +305,19 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
305 | { | 305 | { |
306 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 306 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
307 | 307 | ||
308 | if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { | 308 | if (!info->control.hw_key) { |
309 | if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key, | 309 | if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key, |
310 | tx->key->conf.keylen, | 310 | tx->key->conf.keylen, |
311 | tx->key->conf.keyidx)) | 311 | tx->key->conf.keyidx)) |
312 | return -1; | 312 | return -1; |
313 | } else { | 313 | } else if (info->control.hw_key->flags & |
314 | info->control.hw_key = &tx->key->conf; | 314 | IEEE80211_KEY_FLAG_GENERATE_IV) { |
315 | if (tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) { | 315 | if (!ieee80211_wep_add_iv(tx->local, skb, |
316 | if (!ieee80211_wep_add_iv(tx->local, skb, | 316 | tx->key->conf.keylen, |
317 | tx->key->conf.keylen, | 317 | tx->key->conf.keyidx)) |
318 | tx->key->conf.keyidx)) | 318 | return -1; |
319 | return -1; | ||
320 | } | ||
321 | } | 319 | } |
320 | |||
322 | return 0; | 321 | return 0; |
323 | } | 322 | } |
324 | 323 | ||
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 81bd5d592bb4..7e708d5c88b4 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
@@ -535,8 +535,7 @@ ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk) | |||
535 | * First time we run, do nothing -- the generic code will | 535 | * First time we run, do nothing -- the generic code will |
536 | * have switched to the right channel etc. | 536 | * have switched to the right channel etc. |
537 | */ | 537 | */ |
538 | if (!wk->remain.started) { | 538 | if (!wk->started) { |
539 | wk->remain.started = true; | ||
540 | wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration); | 539 | wk->timeout = jiffies + msecs_to_jiffies(wk->remain.duration); |
541 | 540 | ||
542 | cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk, | 541 | cfg80211_ready_on_channel(wk->sdata->dev, (unsigned long) wk, |
@@ -821,15 +820,17 @@ static void ieee80211_work_work(struct work_struct *work) | |||
821 | mutex_lock(&local->work_mtx); | 820 | mutex_lock(&local->work_mtx); |
822 | 821 | ||
823 | list_for_each_entry_safe(wk, tmp, &local->work_list, list) { | 822 | list_for_each_entry_safe(wk, tmp, &local->work_list, list) { |
823 | bool started = wk->started; | ||
824 | |||
824 | /* mark work as started if it's on the current off-channel */ | 825 | /* mark work as started if it's on the current off-channel */ |
825 | if (!wk->started && local->tmp_channel && | 826 | if (!started && local->tmp_channel && |
826 | wk->chan == local->tmp_channel && | 827 | wk->chan == local->tmp_channel && |
827 | wk->chan_type == local->tmp_channel_type) { | 828 | wk->chan_type == local->tmp_channel_type) { |
828 | wk->started = true; | 829 | started = true; |
829 | wk->timeout = jiffies; | 830 | wk->timeout = jiffies; |
830 | } | 831 | } |
831 | 832 | ||
832 | if (!wk->started && !local->tmp_channel) { | 833 | if (!started && !local->tmp_channel) { |
833 | /* | 834 | /* |
834 | * TODO: could optimize this by leaving the | 835 | * TODO: could optimize this by leaving the |
835 | * station vifs in awake mode if they | 836 | * station vifs in awake mode if they |
@@ -842,12 +843,12 @@ static void ieee80211_work_work(struct work_struct *work) | |||
842 | local->tmp_channel = wk->chan; | 843 | local->tmp_channel = wk->chan; |
843 | local->tmp_channel_type = wk->chan_type; | 844 | local->tmp_channel_type = wk->chan_type; |
844 | ieee80211_hw_config(local, 0); | 845 | ieee80211_hw_config(local, 0); |
845 | wk->started = true; | 846 | started = true; |
846 | wk->timeout = jiffies; | 847 | wk->timeout = jiffies; |
847 | } | 848 | } |
848 | 849 | ||
849 | /* don't try to work with items that aren't started */ | 850 | /* don't try to work with items that aren't started */ |
850 | if (!wk->started) | 851 | if (!started) |
851 | continue; | 852 | continue; |
852 | 853 | ||
853 | if (time_is_after_jiffies(wk->timeout)) { | 854 | if (time_is_after_jiffies(wk->timeout)) { |
@@ -882,6 +883,8 @@ static void ieee80211_work_work(struct work_struct *work) | |||
882 | break; | 883 | break; |
883 | } | 884 | } |
884 | 885 | ||
886 | wk->started = started; | ||
887 | |||
885 | switch (rma) { | 888 | switch (rma) { |
886 | case WORK_ACT_NONE: | 889 | case WORK_ACT_NONE: |
887 | /* might have changed the timeout */ | 890 | /* might have changed the timeout */ |
@@ -1022,8 +1025,6 @@ ieee80211_rx_result ieee80211_work_rx_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1022 | case IEEE80211_STYPE_PROBE_RESP: | 1025 | case IEEE80211_STYPE_PROBE_RESP: |
1023 | case IEEE80211_STYPE_ASSOC_RESP: | 1026 | case IEEE80211_STYPE_ASSOC_RESP: |
1024 | case IEEE80211_STYPE_REASSOC_RESP: | 1027 | case IEEE80211_STYPE_REASSOC_RESP: |
1025 | case IEEE80211_STYPE_DEAUTH: | ||
1026 | case IEEE80211_STYPE_DISASSOC: | ||
1027 | skb_queue_tail(&local->work_skb_queue, skb); | 1028 | skb_queue_tail(&local->work_skb_queue, skb); |
1028 | ieee80211_queue_work(&local->hw, &local->work_work); | 1029 | ieee80211_queue_work(&local->hw, &local->work_work); |
1029 | return RX_QUEUED; | 1030 | return RX_QUEUED; |
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 5332014cb229..f4971cd45c64 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c | |||
@@ -31,8 +31,8 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) | |||
31 | unsigned int hdrlen; | 31 | unsigned int hdrlen; |
32 | struct ieee80211_hdr *hdr; | 32 | struct ieee80211_hdr *hdr; |
33 | struct sk_buff *skb = tx->skb; | 33 | struct sk_buff *skb = tx->skb; |
34 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | ||
34 | int authenticator; | 35 | int authenticator; |
35 | int wpa_test = 0; | ||
36 | int tail; | 36 | int tail; |
37 | 37 | ||
38 | hdr = (struct ieee80211_hdr *)skb->data; | 38 | hdr = (struct ieee80211_hdr *)skb->data; |
@@ -47,16 +47,15 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) | |||
47 | data = skb->data + hdrlen; | 47 | data = skb->data + hdrlen; |
48 | data_len = skb->len - hdrlen; | 48 | data_len = skb->len - hdrlen; |
49 | 49 | ||
50 | if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && | 50 | if (info->control.hw_key && |
51 | !(tx->flags & IEEE80211_TX_FRAGMENTED) && | 51 | !(tx->flags & IEEE80211_TX_FRAGMENTED) && |
52 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) && | 52 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) { |
53 | !wpa_test) { | 53 | /* hwaccel - with no need for SW-generated MMIC */ |
54 | /* hwaccel - with no need for preallocated room for MMIC */ | ||
55 | return TX_CONTINUE; | 54 | return TX_CONTINUE; |
56 | } | 55 | } |
57 | 56 | ||
58 | tail = MICHAEL_MIC_LEN; | 57 | tail = MICHAEL_MIC_LEN; |
59 | if (!(tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) | 58 | if (!info->control.hw_key) |
60 | tail += TKIP_ICV_LEN; | 59 | tail += TKIP_ICV_LEN; |
61 | 60 | ||
62 | if (WARN_ON(skb_tailroom(skb) < tail || | 61 | if (WARN_ON(skb_tailroom(skb) < tail || |
@@ -147,17 +146,16 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
147 | int len, tail; | 146 | int len, tail; |
148 | u8 *pos; | 147 | u8 *pos; |
149 | 148 | ||
150 | if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && | 149 | if (info->control.hw_key && |
151 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { | 150 | !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { |
152 | /* hwaccel - with no need for preallocated room for IV/ICV */ | 151 | /* hwaccel - with no need for software-generated IV */ |
153 | info->control.hw_key = &tx->key->conf; | ||
154 | return 0; | 152 | return 0; |
155 | } | 153 | } |
156 | 154 | ||
157 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 155 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
158 | len = skb->len - hdrlen; | 156 | len = skb->len - hdrlen; |
159 | 157 | ||
160 | if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) | 158 | if (info->control.hw_key) |
161 | tail = 0; | 159 | tail = 0; |
162 | else | 160 | else |
163 | tail = TKIP_ICV_LEN; | 161 | tail = TKIP_ICV_LEN; |
@@ -175,13 +173,11 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
175 | if (key->u.tkip.tx.iv16 == 0) | 173 | if (key->u.tkip.tx.iv16 == 0) |
176 | key->u.tkip.tx.iv32++; | 174 | key->u.tkip.tx.iv32++; |
177 | 175 | ||
178 | if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { | 176 | pos = ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16); |
179 | /* hwaccel - with preallocated room for IV */ | ||
180 | ieee80211_tkip_add_iv(pos, key, key->u.tkip.tx.iv16); | ||
181 | 177 | ||
182 | info->control.hw_key = &tx->key->conf; | 178 | /* hwaccel - with software IV */ |
179 | if (info->control.hw_key) | ||
183 | return 0; | 180 | return 0; |
184 | } | ||
185 | 181 | ||
186 | /* Add room for ICV */ | 182 | /* Add room for ICV */ |
187 | skb_put(skb, TKIP_ICV_LEN); | 183 | skb_put(skb, TKIP_ICV_LEN); |
@@ -363,24 +359,20 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
363 | int hdrlen, len, tail; | 359 | int hdrlen, len, tail; |
364 | u8 *pos, *pn; | 360 | u8 *pos, *pn; |
365 | int i; | 361 | int i; |
366 | bool skip_hw; | ||
367 | |||
368 | skip_hw = (tx->key->conf.flags & IEEE80211_KEY_FLAG_SW_MGMT) && | ||
369 | ieee80211_is_mgmt(hdr->frame_control); | ||
370 | 362 | ||
371 | if ((tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && | 363 | if (info->control.hw_key && |
372 | !(tx->key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) && | 364 | !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { |
373 | !skip_hw) { | 365 | /* |
374 | /* hwaccel - with no need for preallocated room for CCMP | 366 | * hwaccel has no need for preallocated room for CCMP |
375 | * header or MIC fields */ | 367 | * header or MIC fields |
376 | info->control.hw_key = &tx->key->conf; | 368 | */ |
377 | return 0; | 369 | return 0; |
378 | } | 370 | } |
379 | 371 | ||
380 | hdrlen = ieee80211_hdrlen(hdr->frame_control); | 372 | hdrlen = ieee80211_hdrlen(hdr->frame_control); |
381 | len = skb->len - hdrlen; | 373 | len = skb->len - hdrlen; |
382 | 374 | ||
383 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) | 375 | if (info->control.hw_key) |
384 | tail = 0; | 376 | tail = 0; |
385 | else | 377 | else |
386 | tail = CCMP_MIC_LEN; | 378 | tail = CCMP_MIC_LEN; |
@@ -405,11 +397,9 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) | |||
405 | 397 | ||
406 | ccmp_pn2hdr(pos, pn, key->conf.keyidx); | 398 | ccmp_pn2hdr(pos, pn, key->conf.keyidx); |
407 | 399 | ||
408 | if ((key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && !skip_hw) { | 400 | /* hwaccel - with software CCMP header */ |
409 | /* hwaccel - with preallocated room for CCMP header */ | 401 | if (info->control.hw_key) |
410 | info->control.hw_key = &tx->key->conf; | ||
411 | return 0; | 402 | return 0; |
412 | } | ||
413 | 403 | ||
414 | pos += CCMP_HDR_LEN; | 404 | pos += CCMP_HDR_LEN; |
415 | ccmp_special_blocks(skb, pn, key->u.ccmp.tx_crypto_buf, 0); | 405 | ccmp_special_blocks(skb, pn, key->u.ccmp.tx_crypto_buf, 0); |
@@ -525,11 +515,8 @@ ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx) | |||
525 | u8 *pn, aad[20]; | 515 | u8 *pn, aad[20]; |
526 | int i; | 516 | int i; |
527 | 517 | ||
528 | if (tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { | 518 | if (info->control.hw_key) |
529 | /* hwaccel */ | ||
530 | info->control.hw_key = &tx->key->conf; | ||
531 | return 0; | 519 | return 0; |
532 | } | ||
533 | 520 | ||
534 | if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) | 521 | if (WARN_ON(skb_tailroom(skb) < sizeof(*mmie))) |
535 | return TX_DROP; | 522 | return TX_DROP; |
diff --git a/net/wireless/core.c b/net/wireless/core.c index 20db90246de5..71b6b3a9cf1f 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * This is the linux wireless configuration interface. | 2 | * This is the linux wireless configuration interface. |
3 | * | 3 | * |
4 | * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/if.h> | 7 | #include <linux/if.h> |
@@ -31,15 +31,10 @@ MODULE_AUTHOR("Johannes Berg"); | |||
31 | MODULE_LICENSE("GPL"); | 31 | MODULE_LICENSE("GPL"); |
32 | MODULE_DESCRIPTION("wireless configuration support"); | 32 | MODULE_DESCRIPTION("wireless configuration support"); |
33 | 33 | ||
34 | /* RCU might be appropriate here since we usually | 34 | /* RCU-protected (and cfg80211_mutex for writers) */ |
35 | * only read the list, and that can happen quite | ||
36 | * often because we need to do it for each command */ | ||
37 | LIST_HEAD(cfg80211_rdev_list); | 35 | LIST_HEAD(cfg80211_rdev_list); |
38 | int cfg80211_rdev_list_generation; | 36 | int cfg80211_rdev_list_generation; |
39 | 37 | ||
40 | /* | ||
41 | * This is used to protect the cfg80211_rdev_list | ||
42 | */ | ||
43 | DEFINE_MUTEX(cfg80211_mutex); | 38 | DEFINE_MUTEX(cfg80211_mutex); |
44 | 39 | ||
45 | /* for debugfs */ | 40 | /* for debugfs */ |
@@ -418,6 +413,18 @@ int wiphy_register(struct wiphy *wiphy) | |||
418 | int i; | 413 | int i; |
419 | u16 ifmodes = wiphy->interface_modes; | 414 | u16 ifmodes = wiphy->interface_modes; |
420 | 415 | ||
416 | if (WARN_ON(wiphy->addresses && !wiphy->n_addresses)) | ||
417 | return -EINVAL; | ||
418 | |||
419 | if (WARN_ON(wiphy->addresses && | ||
420 | !is_zero_ether_addr(wiphy->perm_addr) && | ||
421 | memcmp(wiphy->perm_addr, wiphy->addresses[0].addr, | ||
422 | ETH_ALEN))) | ||
423 | return -EINVAL; | ||
424 | |||
425 | if (wiphy->addresses) | ||
426 | memcpy(wiphy->perm_addr, wiphy->addresses[0].addr, ETH_ALEN); | ||
427 | |||
421 | /* sanity check ifmodes */ | 428 | /* sanity check ifmodes */ |
422 | WARN_ON(!ifmodes); | 429 | WARN_ON(!ifmodes); |
423 | ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; | 430 | ifmodes &= ((1 << __NL80211_IFTYPE_AFTER_LAST) - 1) & ~1; |
@@ -477,7 +484,7 @@ int wiphy_register(struct wiphy *wiphy) | |||
477 | /* set up regulatory info */ | 484 | /* set up regulatory info */ |
478 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); | 485 | wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); |
479 | 486 | ||
480 | list_add(&rdev->list, &cfg80211_rdev_list); | 487 | list_add_rcu(&rdev->list, &cfg80211_rdev_list); |
481 | cfg80211_rdev_list_generation++; | 488 | cfg80211_rdev_list_generation++; |
482 | 489 | ||
483 | mutex_unlock(&cfg80211_mutex); | 490 | mutex_unlock(&cfg80211_mutex); |
@@ -554,7 +561,8 @@ void wiphy_unregister(struct wiphy *wiphy) | |||
554 | * it impossible to find from userspace. | 561 | * it impossible to find from userspace. |
555 | */ | 562 | */ |
556 | debugfs_remove_recursive(rdev->wiphy.debugfsdir); | 563 | debugfs_remove_recursive(rdev->wiphy.debugfsdir); |
557 | list_del(&rdev->list); | 564 | list_del_rcu(&rdev->list); |
565 | synchronize_rcu(); | ||
558 | 566 | ||
559 | /* | 567 | /* |
560 | * Try to grab rdev->mtx. If a command is still in progress, | 568 | * Try to grab rdev->mtx. If a command is still in progress, |
@@ -670,7 +678,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
670 | INIT_LIST_HEAD(&wdev->event_list); | 678 | INIT_LIST_HEAD(&wdev->event_list); |
671 | spin_lock_init(&wdev->event_lock); | 679 | spin_lock_init(&wdev->event_lock); |
672 | mutex_lock(&rdev->devlist_mtx); | 680 | mutex_lock(&rdev->devlist_mtx); |
673 | list_add(&wdev->list, &rdev->netdev_list); | 681 | list_add_rcu(&wdev->list, &rdev->netdev_list); |
674 | rdev->devlist_generation++; | 682 | rdev->devlist_generation++; |
675 | /* can only change netns with wiphy */ | 683 | /* can only change netns with wiphy */ |
676 | dev->features |= NETIF_F_NETNS_LOCAL; | 684 | dev->features |= NETIF_F_NETNS_LOCAL; |
@@ -782,13 +790,21 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb, | |||
782 | */ | 790 | */ |
783 | if (!list_empty(&wdev->list)) { | 791 | if (!list_empty(&wdev->list)) { |
784 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); | 792 | sysfs_remove_link(&dev->dev.kobj, "phy80211"); |
785 | list_del_init(&wdev->list); | 793 | list_del_rcu(&wdev->list); |
786 | rdev->devlist_generation++; | 794 | rdev->devlist_generation++; |
787 | #ifdef CONFIG_CFG80211_WEXT | 795 | #ifdef CONFIG_CFG80211_WEXT |
788 | kfree(wdev->wext.keys); | 796 | kfree(wdev->wext.keys); |
789 | #endif | 797 | #endif |
790 | } | 798 | } |
791 | mutex_unlock(&rdev->devlist_mtx); | 799 | mutex_unlock(&rdev->devlist_mtx); |
800 | /* | ||
801 | * synchronise (so that we won't find this netdev | ||
802 | * from other code any more) and then clear the list | ||
803 | * head so that the above code can safely check for | ||
804 | * !list_empty() to avoid double-cleanup. | ||
805 | */ | ||
806 | synchronize_rcu(); | ||
807 | INIT_LIST_HEAD(&wdev->list); | ||
792 | break; | 808 | break; |
793 | case NETDEV_PRE_UP: | 809 | case NETDEV_PRE_UP: |
794 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) | 810 | if (!(wdev->wiphy->interface_modes & BIT(wdev->iftype))) |
diff --git a/net/wireless/core.h b/net/wireless/core.h index 2d6a6b9c0c43..c326a667022a 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Wireless configuration interface internals. | 2 | * Wireless configuration interface internals. |
3 | * | 3 | * |
4 | * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net> | 4 | * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net> |
5 | */ | 5 | */ |
6 | #ifndef __NET_WIRELESS_CORE_H | 6 | #ifndef __NET_WIRELESS_CORE_H |
7 | #define __NET_WIRELESS_CORE_H | 7 | #define __NET_WIRELESS_CORE_H |
@@ -48,6 +48,7 @@ struct cfg80211_registered_device { | |||
48 | 48 | ||
49 | /* associate netdev list */ | 49 | /* associate netdev list */ |
50 | struct mutex devlist_mtx; | 50 | struct mutex devlist_mtx; |
51 | /* protected by devlist_mtx or RCU */ | ||
51 | struct list_head netdev_list; | 52 | struct list_head netdev_list; |
52 | int devlist_generation; | 53 | int devlist_generation; |
53 | int opencount; /* also protected by devlist_mtx */ | 54 | int opencount; /* also protected by devlist_mtx */ |
diff --git a/net/wireless/lib80211_crypt_ccmp.c b/net/wireless/lib80211_crypt_ccmp.c index 2301dc1edc4c..b7fa31d5fd13 100644 --- a/net/wireless/lib80211_crypt_ccmp.c +++ b/net/wireless/lib80211_crypt_ccmp.c | |||
@@ -237,7 +237,6 @@ static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) | |||
237 | return -1; | 237 | return -1; |
238 | 238 | ||
239 | pos = skb->data + hdr_len + CCMP_HDR_LEN; | 239 | pos = skb->data + hdr_len + CCMP_HDR_LEN; |
240 | mic = skb_put(skb, CCMP_MIC_LEN); | ||
241 | hdr = (struct ieee80211_hdr *)skb->data; | 240 | hdr = (struct ieee80211_hdr *)skb->data; |
242 | ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); | 241 | ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); |
243 | 242 | ||
@@ -257,6 +256,7 @@ static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) | |||
257 | pos += len; | 256 | pos += len; |
258 | } | 257 | } |
259 | 258 | ||
259 | mic = skb_put(skb, CCMP_MIC_LEN); | ||
260 | for (i = 0; i < CCMP_MIC_LEN; i++) | 260 | for (i = 0; i < CCMP_MIC_LEN; i++) |
261 | mic[i] = b[i] ^ s0[i]; | 261 | mic[i] = b[i] ^ s0[i]; |
262 | 262 | ||
diff --git a/net/wireless/lib80211_crypt_tkip.c b/net/wireless/lib80211_crypt_tkip.c index c36287399d7e..8cbdb32ff316 100644 --- a/net/wireless/lib80211_crypt_tkip.c +++ b/net/wireless/lib80211_crypt_tkip.c | |||
@@ -36,6 +36,8 @@ MODULE_AUTHOR("Jouni Malinen"); | |||
36 | MODULE_DESCRIPTION("lib80211 crypt: TKIP"); | 36 | MODULE_DESCRIPTION("lib80211 crypt: TKIP"); |
37 | MODULE_LICENSE("GPL"); | 37 | MODULE_LICENSE("GPL"); |
38 | 38 | ||
39 | #define TKIP_HDR_LEN 8 | ||
40 | |||
39 | struct lib80211_tkip_data { | 41 | struct lib80211_tkip_data { |
40 | #define TKIP_KEY_LEN 32 | 42 | #define TKIP_KEY_LEN 32 |
41 | u8 key[TKIP_KEY_LEN]; | 43 | u8 key[TKIP_KEY_LEN]; |
@@ -314,13 +316,12 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len, | |||
314 | u8 * rc4key, int keylen, void *priv) | 316 | u8 * rc4key, int keylen, void *priv) |
315 | { | 317 | { |
316 | struct lib80211_tkip_data *tkey = priv; | 318 | struct lib80211_tkip_data *tkey = priv; |
317 | int len; | ||
318 | u8 *pos; | 319 | u8 *pos; |
319 | struct ieee80211_hdr *hdr; | 320 | struct ieee80211_hdr *hdr; |
320 | 321 | ||
321 | hdr = (struct ieee80211_hdr *)skb->data; | 322 | hdr = (struct ieee80211_hdr *)skb->data; |
322 | 323 | ||
323 | if (skb_headroom(skb) < 8 || skb->len < hdr_len) | 324 | if (skb_headroom(skb) < TKIP_HDR_LEN || skb->len < hdr_len) |
324 | return -1; | 325 | return -1; |
325 | 326 | ||
326 | if (rc4key == NULL || keylen < 16) | 327 | if (rc4key == NULL || keylen < 16) |
@@ -333,9 +334,8 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len, | |||
333 | } | 334 | } |
334 | tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); | 335 | tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16); |
335 | 336 | ||
336 | len = skb->len - hdr_len; | 337 | pos = skb_push(skb, TKIP_HDR_LEN); |
337 | pos = skb_push(skb, 8); | 338 | memmove(pos, pos + TKIP_HDR_LEN, hdr_len); |
338 | memmove(pos, pos + 8, hdr_len); | ||
339 | pos += hdr_len; | 339 | pos += hdr_len; |
340 | 340 | ||
341 | *pos++ = *rc4key; | 341 | *pos++ = *rc4key; |
@@ -353,7 +353,7 @@ static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len, | |||
353 | tkey->tx_iv32++; | 353 | tkey->tx_iv32++; |
354 | } | 354 | } |
355 | 355 | ||
356 | return 8; | 356 | return TKIP_HDR_LEN; |
357 | } | 357 | } |
358 | 358 | ||
359 | static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) | 359 | static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) |
@@ -384,9 +384,8 @@ static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) | |||
384 | if ((lib80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0) | 384 | if ((lib80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0) |
385 | return -1; | 385 | return -1; |
386 | 386 | ||
387 | icv = skb_put(skb, 4); | ||
388 | |||
389 | crc = ~crc32_le(~0, pos, len); | 387 | crc = ~crc32_le(~0, pos, len); |
388 | icv = skb_put(skb, 4); | ||
390 | icv[0] = crc; | 389 | icv[0] = crc; |
391 | icv[1] = crc >> 8; | 390 | icv[1] = crc >> 8; |
392 | icv[2] = crc >> 16; | 391 | icv[2] = crc >> 16; |
@@ -434,7 +433,7 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) | |||
434 | return -1; | 433 | return -1; |
435 | } | 434 | } |
436 | 435 | ||
437 | if (skb->len < hdr_len + 8 + 4) | 436 | if (skb->len < hdr_len + TKIP_HDR_LEN + 4) |
438 | return -1; | 437 | return -1; |
439 | 438 | ||
440 | pos = skb->data + hdr_len; | 439 | pos = skb->data + hdr_len; |
@@ -462,7 +461,7 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) | |||
462 | } | 461 | } |
463 | iv16 = (pos[0] << 8) | pos[2]; | 462 | iv16 = (pos[0] << 8) | pos[2]; |
464 | iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); | 463 | iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24); |
465 | pos += 8; | 464 | pos += TKIP_HDR_LEN; |
466 | 465 | ||
467 | if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) { | 466 | if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) { |
468 | #ifdef CONFIG_LIB80211_DEBUG | 467 | #ifdef CONFIG_LIB80211_DEBUG |
@@ -523,8 +522,8 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) | |||
523 | tkey->rx_iv16_new = iv16; | 522 | tkey->rx_iv16_new = iv16; |
524 | 523 | ||
525 | /* Remove IV and ICV */ | 524 | /* Remove IV and ICV */ |
526 | memmove(skb->data + 8, skb->data, hdr_len); | 525 | memmove(skb->data + TKIP_HDR_LEN, skb->data, hdr_len); |
527 | skb_pull(skb, 8); | 526 | skb_pull(skb, TKIP_HDR_LEN); |
528 | skb_trim(skb, skb->len - 4); | 527 | skb_trim(skb, skb->len - 4); |
529 | 528 | ||
530 | return keyidx; | 529 | return keyidx; |
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 4af7991a9ec8..5b79ecf17bea 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c | |||
@@ -3571,6 +3571,7 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3571 | { | 3571 | { |
3572 | struct cfg80211_registered_device *rdev; | 3572 | struct cfg80211_registered_device *rdev; |
3573 | struct net_device *dev; | 3573 | struct net_device *dev; |
3574 | struct wireless_dev *wdev; | ||
3574 | struct cfg80211_crypto_settings crypto; | 3575 | struct cfg80211_crypto_settings crypto; |
3575 | struct ieee80211_channel *chan, *fixedchan; | 3576 | struct ieee80211_channel *chan, *fixedchan; |
3576 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; | 3577 | const u8 *bssid, *ssid, *ie = NULL, *prev_bssid = NULL; |
@@ -3616,7 +3617,8 @@ static int nl80211_associate(struct sk_buff *skb, struct genl_info *info) | |||
3616 | } | 3617 | } |
3617 | 3618 | ||
3618 | mutex_lock(&rdev->devlist_mtx); | 3619 | mutex_lock(&rdev->devlist_mtx); |
3619 | fixedchan = rdev_fixed_channel(rdev, NULL); | 3620 | wdev = dev->ieee80211_ptr; |
3621 | fixedchan = rdev_fixed_channel(rdev, wdev); | ||
3620 | if (fixedchan && chan != fixedchan) { | 3622 | if (fixedchan && chan != fixedchan) { |
3621 | err = -EBUSY; | 3623 | err = -EBUSY; |
3622 | mutex_unlock(&rdev->devlist_mtx); | 3624 | mutex_unlock(&rdev->devlist_mtx); |
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 5f8071de7950..ed89c59bb431 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -134,6 +134,7 @@ static const struct ieee80211_regdomain *cfg80211_world_regdom = | |||
134 | &world_regdom; | 134 | &world_regdom; |
135 | 135 | ||
136 | static char *ieee80211_regdom = "00"; | 136 | static char *ieee80211_regdom = "00"; |
137 | static char user_alpha2[2]; | ||
137 | 138 | ||
138 | module_param(ieee80211_regdom, charp, 0444); | 139 | module_param(ieee80211_regdom, charp, 0444); |
139 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); | 140 | MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code"); |
@@ -252,6 +253,27 @@ static bool regdom_changes(const char *alpha2) | |||
252 | return true; | 253 | return true; |
253 | } | 254 | } |
254 | 255 | ||
256 | /* | ||
257 | * The NL80211_REGDOM_SET_BY_USER regdom alpha2 is cached, this lets | ||
258 | * you know if a valid regulatory hint with NL80211_REGDOM_SET_BY_USER | ||
259 | * has ever been issued. | ||
260 | */ | ||
261 | static bool is_user_regdom_saved(void) | ||
262 | { | ||
263 | if (user_alpha2[0] == '9' && user_alpha2[1] == '7') | ||
264 | return false; | ||
265 | |||
266 | /* This would indicate a mistake on the design */ | ||
267 | if (WARN((!is_world_regdom(user_alpha2) && | ||
268 | !is_an_alpha2(user_alpha2)), | ||
269 | "Unexpected user alpha2: %c%c\n", | ||
270 | user_alpha2[0], | ||
271 | user_alpha2[1])) | ||
272 | return false; | ||
273 | |||
274 | return true; | ||
275 | } | ||
276 | |||
255 | /** | 277 | /** |
256 | * country_ie_integrity_changes - tells us if the country IE has changed | 278 | * country_ie_integrity_changes - tells us if the country IE has changed |
257 | * @checksum: checksum of country IE of fields we are interested in | 279 | * @checksum: checksum of country IE of fields we are interested in |
@@ -1646,7 +1668,7 @@ static int ignore_request(struct wiphy *wiphy, | |||
1646 | 1668 | ||
1647 | switch (pending_request->initiator) { | 1669 | switch (pending_request->initiator) { |
1648 | case NL80211_REGDOM_SET_BY_CORE: | 1670 | case NL80211_REGDOM_SET_BY_CORE: |
1649 | return -EINVAL; | 1671 | return 0; |
1650 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: | 1672 | case NL80211_REGDOM_SET_BY_COUNTRY_IE: |
1651 | 1673 | ||
1652 | last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); | 1674 | last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); |
@@ -1785,6 +1807,11 @@ new_request: | |||
1785 | 1807 | ||
1786 | pending_request = NULL; | 1808 | pending_request = NULL; |
1787 | 1809 | ||
1810 | if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) { | ||
1811 | user_alpha2[0] = last_request->alpha2[0]; | ||
1812 | user_alpha2[1] = last_request->alpha2[1]; | ||
1813 | } | ||
1814 | |||
1788 | /* When r == REG_INTERSECT we do need to call CRDA */ | 1815 | /* When r == REG_INTERSECT we do need to call CRDA */ |
1789 | if (r < 0) { | 1816 | if (r < 0) { |
1790 | /* | 1817 | /* |
@@ -1904,12 +1931,16 @@ static void queue_regulatory_request(struct regulatory_request *request) | |||
1904 | schedule_work(®_work); | 1931 | schedule_work(®_work); |
1905 | } | 1932 | } |
1906 | 1933 | ||
1907 | /* Core regulatory hint -- happens once during cfg80211_init() */ | 1934 | /* |
1935 | * Core regulatory hint -- happens during cfg80211_init() | ||
1936 | * and when we restore regulatory settings. | ||
1937 | */ | ||
1908 | static int regulatory_hint_core(const char *alpha2) | 1938 | static int regulatory_hint_core(const char *alpha2) |
1909 | { | 1939 | { |
1910 | struct regulatory_request *request; | 1940 | struct regulatory_request *request; |
1911 | 1941 | ||
1912 | BUG_ON(last_request); | 1942 | kfree(last_request); |
1943 | last_request = NULL; | ||
1913 | 1944 | ||
1914 | request = kzalloc(sizeof(struct regulatory_request), | 1945 | request = kzalloc(sizeof(struct regulatory_request), |
1915 | GFP_KERNEL); | 1946 | GFP_KERNEL); |
@@ -1920,14 +1951,12 @@ static int regulatory_hint_core(const char *alpha2) | |||
1920 | request->alpha2[1] = alpha2[1]; | 1951 | request->alpha2[1] = alpha2[1]; |
1921 | request->initiator = NL80211_REGDOM_SET_BY_CORE; | 1952 | request->initiator = NL80211_REGDOM_SET_BY_CORE; |
1922 | 1953 | ||
1923 | queue_regulatory_request(request); | ||
1924 | |||
1925 | /* | 1954 | /* |
1926 | * This ensures last_request is populated once modules | 1955 | * This ensures last_request is populated once modules |
1927 | * come swinging in and calling regulatory hints and | 1956 | * come swinging in and calling regulatory hints and |
1928 | * wiphy_apply_custom_regulatory(). | 1957 | * wiphy_apply_custom_regulatory(). |
1929 | */ | 1958 | */ |
1930 | flush_scheduled_work(); | 1959 | reg_process_hint(request); |
1931 | 1960 | ||
1932 | return 0; | 1961 | return 0; |
1933 | } | 1962 | } |
@@ -2109,6 +2138,123 @@ out: | |||
2109 | mutex_unlock(®_mutex); | 2138 | mutex_unlock(®_mutex); |
2110 | } | 2139 | } |
2111 | 2140 | ||
2141 | static void restore_alpha2(char *alpha2, bool reset_user) | ||
2142 | { | ||
2143 | /* indicates there is no alpha2 to consider for restoration */ | ||
2144 | alpha2[0] = '9'; | ||
2145 | alpha2[1] = '7'; | ||
2146 | |||
2147 | /* The user setting has precedence over the module parameter */ | ||
2148 | if (is_user_regdom_saved()) { | ||
2149 | /* Unless we're asked to ignore it and reset it */ | ||
2150 | if (reset_user) { | ||
2151 | REG_DBG_PRINT("cfg80211: Restoring regulatory settings " | ||
2152 | "including user preference\n"); | ||
2153 | user_alpha2[0] = '9'; | ||
2154 | user_alpha2[1] = '7'; | ||
2155 | |||
2156 | /* | ||
2157 | * If we're ignoring user settings, we still need to | ||
2158 | * check the module parameter to ensure we put things | ||
2159 | * back as they were for a full restore. | ||
2160 | */ | ||
2161 | if (!is_world_regdom(ieee80211_regdom)) { | ||
2162 | REG_DBG_PRINT("cfg80211: Keeping preference on " | ||
2163 | "module parameter ieee80211_regdom: %c%c\n", | ||
2164 | ieee80211_regdom[0], | ||
2165 | ieee80211_regdom[1]); | ||
2166 | alpha2[0] = ieee80211_regdom[0]; | ||
2167 | alpha2[1] = ieee80211_regdom[1]; | ||
2168 | } | ||
2169 | } else { | ||
2170 | REG_DBG_PRINT("cfg80211: Restoring regulatory settings " | ||
2171 | "while preserving user preference for: %c%c\n", | ||
2172 | user_alpha2[0], | ||
2173 | user_alpha2[1]); | ||
2174 | alpha2[0] = user_alpha2[0]; | ||
2175 | alpha2[1] = user_alpha2[1]; | ||
2176 | } | ||
2177 | } else if (!is_world_regdom(ieee80211_regdom)) { | ||
2178 | REG_DBG_PRINT("cfg80211: Keeping preference on " | ||
2179 | "module parameter ieee80211_regdom: %c%c\n", | ||
2180 | ieee80211_regdom[0], | ||
2181 | ieee80211_regdom[1]); | ||
2182 | alpha2[0] = ieee80211_regdom[0]; | ||
2183 | alpha2[1] = ieee80211_regdom[1]; | ||
2184 | } else | ||
2185 | REG_DBG_PRINT("cfg80211: Restoring regulatory settings\n"); | ||
2186 | } | ||
2187 | |||
2188 | /* | ||
2189 | * Restoring regulatory settings involves ingoring any | ||
2190 | * possibly stale country IE information and user regulatory | ||
2191 | * settings if so desired, this includes any beacon hints | ||
2192 | * learned as we could have traveled outside to another country | ||
2193 | * after disconnection. To restore regulatory settings we do | ||
2194 | * exactly what we did at bootup: | ||
2195 | * | ||
2196 | * - send a core regulatory hint | ||
2197 | * - send a user regulatory hint if applicable | ||
2198 | * | ||
2199 | * Device drivers that send a regulatory hint for a specific country | ||
2200 | * keep their own regulatory domain on wiphy->regd so that does does | ||
2201 | * not need to be remembered. | ||
2202 | */ | ||
2203 | static void restore_regulatory_settings(bool reset_user) | ||
2204 | { | ||
2205 | char alpha2[2]; | ||
2206 | struct reg_beacon *reg_beacon, *btmp; | ||
2207 | |||
2208 | mutex_lock(&cfg80211_mutex); | ||
2209 | mutex_lock(®_mutex); | ||
2210 | |||
2211 | reset_regdomains(); | ||
2212 | restore_alpha2(alpha2, reset_user); | ||
2213 | |||
2214 | /* Clear beacon hints */ | ||
2215 | spin_lock_bh(®_pending_beacons_lock); | ||
2216 | if (!list_empty(®_pending_beacons)) { | ||
2217 | list_for_each_entry_safe(reg_beacon, btmp, | ||
2218 | ®_pending_beacons, list) { | ||
2219 | list_del(®_beacon->list); | ||
2220 | kfree(reg_beacon); | ||
2221 | } | ||
2222 | } | ||
2223 | spin_unlock_bh(®_pending_beacons_lock); | ||
2224 | |||
2225 | if (!list_empty(®_beacon_list)) { | ||
2226 | list_for_each_entry_safe(reg_beacon, btmp, | ||
2227 | ®_beacon_list, list) { | ||
2228 | list_del(®_beacon->list); | ||
2229 | kfree(reg_beacon); | ||
2230 | } | ||
2231 | } | ||
2232 | |||
2233 | /* First restore to the basic regulatory settings */ | ||
2234 | cfg80211_regdomain = cfg80211_world_regdom; | ||
2235 | |||
2236 | mutex_unlock(®_mutex); | ||
2237 | mutex_unlock(&cfg80211_mutex); | ||
2238 | |||
2239 | regulatory_hint_core(cfg80211_regdomain->alpha2); | ||
2240 | |||
2241 | /* | ||
2242 | * This restores the ieee80211_regdom module parameter | ||
2243 | * preference or the last user requested regulatory | ||
2244 | * settings, user regulatory settings takes precedence. | ||
2245 | */ | ||
2246 | if (is_an_alpha2(alpha2)) | ||
2247 | regulatory_hint_user(user_alpha2); | ||
2248 | } | ||
2249 | |||
2250 | |||
2251 | void regulatory_hint_disconnect(void) | ||
2252 | { | ||
2253 | REG_DBG_PRINT("cfg80211: All devices are disconnected, going to " | ||
2254 | "restore regulatory settings\n"); | ||
2255 | restore_regulatory_settings(false); | ||
2256 | } | ||
2257 | |||
2112 | static bool freq_is_chan_12_13_14(u16 freq) | 2258 | static bool freq_is_chan_12_13_14(u16 freq) |
2113 | { | 2259 | { |
2114 | if (freq == ieee80211_channel_to_frequency(12) || | 2260 | if (freq == ieee80211_channel_to_frequency(12) || |
@@ -2498,6 +2644,9 @@ int regulatory_init(void) | |||
2498 | 2644 | ||
2499 | cfg80211_regdomain = cfg80211_world_regdom; | 2645 | cfg80211_regdomain = cfg80211_world_regdom; |
2500 | 2646 | ||
2647 | user_alpha2[0] = '9'; | ||
2648 | user_alpha2[1] = '7'; | ||
2649 | |||
2501 | /* We always try to get an update for the static regdomain */ | 2650 | /* We always try to get an update for the static regdomain */ |
2502 | err = regulatory_hint_core(cfg80211_regdomain->alpha2); | 2651 | err = regulatory_hint_core(cfg80211_regdomain->alpha2); |
2503 | if (err) { | 2652 | if (err) { |
diff --git a/net/wireless/reg.h b/net/wireless/reg.h index 3018508226ab..b26224a9f3bc 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h | |||
@@ -63,4 +63,22 @@ void regulatory_hint_11d(struct wiphy *wiphy, | |||
63 | u8 *country_ie, | 63 | u8 *country_ie, |
64 | u8 country_ie_len); | 64 | u8 country_ie_len); |
65 | 65 | ||
66 | /** | ||
67 | * regulatory_hint_disconnect - informs all devices have been disconneted | ||
68 | * | ||
69 | * Regulotory rules can be enhanced further upon scanning and upon | ||
70 | * connection to an AP. These rules become stale if we disconnect | ||
71 | * and go to another country, whether or not we suspend and resume. | ||
72 | * If we suspend, go to another country and resume we'll automatically | ||
73 | * get disconnected shortly after resuming and things will be reset as well. | ||
74 | * This routine is a helper to restore regulatory settings to how they were | ||
75 | * prior to our first connect attempt. This includes ignoring country IE and | ||
76 | * beacon regulatory hints. The ieee80211_regdom module parameter will always | ||
77 | * be respected but if a user had set the regulatory domain that will take | ||
78 | * precedence. | ||
79 | * | ||
80 | * Must be called from process context. | ||
81 | */ | ||
82 | void regulatory_hint_disconnect(void); | ||
83 | |||
66 | #endif /* __NET_WIRELESS_REG_H */ | 84 | #endif /* __NET_WIRELESS_REG_H */ |
diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 06b0231ee5e3..978cac3414b5 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c | |||
@@ -143,9 +143,9 @@ void cfg80211_bss_expire(struct cfg80211_registered_device *dev) | |||
143 | dev->bss_generation++; | 143 | dev->bss_generation++; |
144 | } | 144 | } |
145 | 145 | ||
146 | static u8 *find_ie(u8 num, u8 *ies, int len) | 146 | const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len) |
147 | { | 147 | { |
148 | while (len > 2 && ies[0] != num) { | 148 | while (len > 2 && ies[0] != eid) { |
149 | len -= ies[1] + 2; | 149 | len -= ies[1] + 2; |
150 | ies += ies[1] + 2; | 150 | ies += ies[1] + 2; |
151 | } | 151 | } |
@@ -155,11 +155,12 @@ static u8 *find_ie(u8 num, u8 *ies, int len) | |||
155 | return NULL; | 155 | return NULL; |
156 | return ies; | 156 | return ies; |
157 | } | 157 | } |
158 | EXPORT_SYMBOL(cfg80211_find_ie); | ||
158 | 159 | ||
159 | static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2) | 160 | static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2) |
160 | { | 161 | { |
161 | const u8 *ie1 = find_ie(num, ies1, len1); | 162 | const u8 *ie1 = cfg80211_find_ie(num, ies1, len1); |
162 | const u8 *ie2 = find_ie(num, ies2, len2); | 163 | const u8 *ie2 = cfg80211_find_ie(num, ies2, len2); |
163 | int r; | 164 | int r; |
164 | 165 | ||
165 | if (!ie1 && !ie2) | 166 | if (!ie1 && !ie2) |
@@ -185,9 +186,9 @@ static bool is_bss(struct cfg80211_bss *a, | |||
185 | if (!ssid) | 186 | if (!ssid) |
186 | return true; | 187 | return true; |
187 | 188 | ||
188 | ssidie = find_ie(WLAN_EID_SSID, | 189 | ssidie = cfg80211_find_ie(WLAN_EID_SSID, |
189 | a->information_elements, | 190 | a->information_elements, |
190 | a->len_information_elements); | 191 | a->len_information_elements); |
191 | if (!ssidie) | 192 | if (!ssidie) |
192 | return false; | 193 | return false; |
193 | if (ssidie[1] != ssid_len) | 194 | if (ssidie[1] != ssid_len) |
@@ -204,9 +205,9 @@ static bool is_mesh(struct cfg80211_bss *a, | |||
204 | if (!is_zero_ether_addr(a->bssid)) | 205 | if (!is_zero_ether_addr(a->bssid)) |
205 | return false; | 206 | return false; |
206 | 207 | ||
207 | ie = find_ie(WLAN_EID_MESH_ID, | 208 | ie = cfg80211_find_ie(WLAN_EID_MESH_ID, |
208 | a->information_elements, | 209 | a->information_elements, |
209 | a->len_information_elements); | 210 | a->len_information_elements); |
210 | if (!ie) | 211 | if (!ie) |
211 | return false; | 212 | return false; |
212 | if (ie[1] != meshidlen) | 213 | if (ie[1] != meshidlen) |
@@ -214,9 +215,9 @@ static bool is_mesh(struct cfg80211_bss *a, | |||
214 | if (memcmp(ie + 2, meshid, meshidlen)) | 215 | if (memcmp(ie + 2, meshid, meshidlen)) |
215 | return false; | 216 | return false; |
216 | 217 | ||
217 | ie = find_ie(WLAN_EID_MESH_CONFIG, | 218 | ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, |
218 | a->information_elements, | 219 | a->information_elements, |
219 | a->len_information_elements); | 220 | a->len_information_elements); |
220 | if (!ie) | 221 | if (!ie) |
221 | return false; | 222 | return false; |
222 | if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) | 223 | if (ie[1] != sizeof(struct ieee80211_meshconf_ie)) |
@@ -395,11 +396,12 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, | |||
395 | 396 | ||
396 | if (is_zero_ether_addr(res->pub.bssid)) { | 397 | if (is_zero_ether_addr(res->pub.bssid)) { |
397 | /* must be mesh, verify */ | 398 | /* must be mesh, verify */ |
398 | meshid = find_ie(WLAN_EID_MESH_ID, res->pub.information_elements, | 399 | meshid = cfg80211_find_ie(WLAN_EID_MESH_ID, |
399 | res->pub.len_information_elements); | 400 | res->pub.information_elements, |
400 | meshcfg = find_ie(WLAN_EID_MESH_CONFIG, | 401 | res->pub.len_information_elements); |
401 | res->pub.information_elements, | 402 | meshcfg = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, |
402 | res->pub.len_information_elements); | 403 | res->pub.information_elements, |
404 | res->pub.len_information_elements); | ||
403 | if (!meshid || !meshcfg || | 405 | if (!meshid || !meshcfg || |
404 | meshcfg[1] != sizeof(struct ieee80211_meshconf_ie)) { | 406 | meshcfg[1] != sizeof(struct ieee80211_meshconf_ie)) { |
405 | /* bogus mesh */ | 407 | /* bogus mesh */ |
diff --git a/net/wireless/sme.c b/net/wireless/sme.c index 745c37e7992e..17fde0da1b08 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c | |||
@@ -34,6 +34,44 @@ struct cfg80211_conn { | |||
34 | bool auto_auth, prev_bssid_valid; | 34 | bool auto_auth, prev_bssid_valid; |
35 | }; | 35 | }; |
36 | 36 | ||
37 | bool cfg80211_is_all_idle(void) | ||
38 | { | ||
39 | struct cfg80211_registered_device *rdev; | ||
40 | struct wireless_dev *wdev; | ||
41 | bool is_all_idle = true; | ||
42 | |||
43 | mutex_lock(&cfg80211_mutex); | ||
44 | |||
45 | /* | ||
46 | * All devices must be idle as otherwise if you are actively | ||
47 | * scanning some new beacon hints could be learned and would | ||
48 | * count as new regulatory hints. | ||
49 | */ | ||
50 | list_for_each_entry(rdev, &cfg80211_rdev_list, list) { | ||
51 | cfg80211_lock_rdev(rdev); | ||
52 | list_for_each_entry(wdev, &rdev->netdev_list, list) { | ||
53 | wdev_lock(wdev); | ||
54 | if (wdev->sme_state != CFG80211_SME_IDLE) | ||
55 | is_all_idle = false; | ||
56 | wdev_unlock(wdev); | ||
57 | } | ||
58 | cfg80211_unlock_rdev(rdev); | ||
59 | } | ||
60 | |||
61 | mutex_unlock(&cfg80211_mutex); | ||
62 | |||
63 | return is_all_idle; | ||
64 | } | ||
65 | |||
66 | static void disconnect_work(struct work_struct *work) | ||
67 | { | ||
68 | if (!cfg80211_is_all_idle()) | ||
69 | return; | ||
70 | |||
71 | regulatory_hint_disconnect(); | ||
72 | } | ||
73 | |||
74 | static DECLARE_WORK(cfg80211_disconnect_work, disconnect_work); | ||
37 | 75 | ||
38 | static int cfg80211_conn_scan(struct wireless_dev *wdev) | 76 | static int cfg80211_conn_scan(struct wireless_dev *wdev) |
39 | { | 77 | { |
@@ -658,6 +696,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie, | |||
658 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); | 696 | wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); |
659 | wdev->wext.connect.ssid_len = 0; | 697 | wdev->wext.connect.ssid_len = 0; |
660 | #endif | 698 | #endif |
699 | |||
700 | schedule_work(&cfg80211_disconnect_work); | ||
661 | } | 701 | } |
662 | 702 | ||
663 | void cfg80211_disconnected(struct net_device *dev, u16 reason, | 703 | void cfg80211_disconnected(struct net_device *dev, u16 reason, |
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index efe3c5c92b2d..9f2cef3e0ca0 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c | |||
@@ -33,10 +33,30 @@ static ssize_t name ## _show(struct device *dev, \ | |||
33 | 33 | ||
34 | SHOW_FMT(index, "%d", wiphy_idx); | 34 | SHOW_FMT(index, "%d", wiphy_idx); |
35 | SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); | 35 | SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); |
36 | SHOW_FMT(address_mask, "%pM", wiphy.addr_mask); | ||
37 | |||
38 | static ssize_t addresses_show(struct device *dev, | ||
39 | struct device_attribute *attr, | ||
40 | char *buf) | ||
41 | { | ||
42 | struct wiphy *wiphy = &dev_to_rdev(dev)->wiphy; | ||
43 | char *start = buf; | ||
44 | int i; | ||
45 | |||
46 | if (!wiphy->addresses) | ||
47 | return sprintf(buf, "%pM\n", wiphy->perm_addr); | ||
48 | |||
49 | for (i = 0; i < wiphy->n_addresses; i++) | ||
50 | buf += sprintf(buf, "%pM\n", &wiphy->addresses[i].addr); | ||
51 | |||
52 | return buf - start; | ||
53 | } | ||
36 | 54 | ||
37 | static struct device_attribute ieee80211_dev_attrs[] = { | 55 | static struct device_attribute ieee80211_dev_attrs[] = { |
38 | __ATTR_RO(index), | 56 | __ATTR_RO(index), |
39 | __ATTR_RO(macaddress), | 57 | __ATTR_RO(macaddress), |
58 | __ATTR_RO(address_mask), | ||
59 | __ATTR_RO(addresses), | ||
40 | {} | 60 | {} |
41 | }; | 61 | }; |
42 | 62 | ||
diff --git a/net/wireless/util.c b/net/wireless/util.c index 23557c1d0a9c..be2ab8c59e3a 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c | |||
@@ -227,8 +227,11 @@ unsigned int ieee80211_hdrlen(__le16 fc) | |||
227 | if (ieee80211_is_data(fc)) { | 227 | if (ieee80211_is_data(fc)) { |
228 | if (ieee80211_has_a4(fc)) | 228 | if (ieee80211_has_a4(fc)) |
229 | hdrlen = 30; | 229 | hdrlen = 30; |
230 | if (ieee80211_is_data_qos(fc)) | 230 | if (ieee80211_is_data_qos(fc)) { |
231 | hdrlen += IEEE80211_QOS_CTL_LEN; | 231 | hdrlen += IEEE80211_QOS_CTL_LEN; |
232 | if (ieee80211_has_order(fc)) | ||
233 | hdrlen += IEEE80211_HT_CTL_LEN; | ||
234 | } | ||
232 | goto out; | 235 | goto out; |
233 | } | 236 | } |
234 | 237 | ||
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 966d2f01beac..b17eeae448d5 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c | |||
@@ -1214,7 +1214,7 @@ int cfg80211_wext_siwrate(struct net_device *dev, | |||
1214 | 1214 | ||
1215 | memset(&mask, 0, sizeof(mask)); | 1215 | memset(&mask, 0, sizeof(mask)); |
1216 | fixed = 0; | 1216 | fixed = 0; |
1217 | maxrate = 0; | 1217 | maxrate = (u32)-1; |
1218 | 1218 | ||
1219 | if (rate->value < 0) { | 1219 | if (rate->value < 0) { |
1220 | /* nothing */ | 1220 | /* nothing */ |