diff options
author | David S. Miller <davem@davemloft.net> | 2010-05-18 00:09:11 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-05-18 00:09:11 -0400 |
commit | 820ae8a80eb59962aefbbd4908dfe144ec0f9edb (patch) | |
tree | 6c0f7356afff14e1c7d266de644810cd2de7caa9 /net | |
parent | 380fefb2ddabd4cd5f14dbe090481f0544e65078 (diff) | |
parent | 6fe70aae0d128339febfabc073ba4c4a03de4f45 (diff) |
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net')
-rw-r--r-- | net/mac80211/driver-ops.h | 11 | ||||
-rw-r--r-- | net/mac80211/driver-trace.h | 49 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 3 | ||||
-rw-r--r-- | net/mac80211/mlme.c | 59 | ||||
-rw-r--r-- | net/mac80211/rx.c | 6 | ||||
-rw-r--r-- | net/mac80211/work.c | 27 |
6 files changed, 147 insertions, 8 deletions
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index ee8b63f92f71..4f2271316650 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h | |||
@@ -371,4 +371,15 @@ static inline void drv_flush(struct ieee80211_local *local, bool drop) | |||
371 | if (local->ops->flush) | 371 | if (local->ops->flush) |
372 | local->ops->flush(&local->hw, drop); | 372 | local->ops->flush(&local->hw, drop); |
373 | } | 373 | } |
374 | |||
375 | static inline void drv_channel_switch(struct ieee80211_local *local, | ||
376 | struct ieee80211_channel_switch *ch_switch) | ||
377 | { | ||
378 | might_sleep(); | ||
379 | |||
380 | local->ops->channel_switch(&local->hw, ch_switch); | ||
381 | |||
382 | trace_drv_channel_switch(local, ch_switch); | ||
383 | } | ||
384 | |||
374 | #endif /* __MAC80211_DRIVER_OPS */ | 385 | #endif /* __MAC80211_DRIVER_OPS */ |
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h index ce734b58d07a..6a9b2342a9c2 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/driver-trace.h | |||
@@ -774,6 +774,34 @@ TRACE_EVENT(drv_flush, | |||
774 | ) | 774 | ) |
775 | ); | 775 | ); |
776 | 776 | ||
777 | TRACE_EVENT(drv_channel_switch, | ||
778 | TP_PROTO(struct ieee80211_local *local, | ||
779 | struct ieee80211_channel_switch *ch_switch), | ||
780 | |||
781 | TP_ARGS(local, ch_switch), | ||
782 | |||
783 | TP_STRUCT__entry( | ||
784 | LOCAL_ENTRY | ||
785 | __field(u64, timestamp) | ||
786 | __field(bool, block_tx) | ||
787 | __field(u16, freq) | ||
788 | __field(u8, count) | ||
789 | ), | ||
790 | |||
791 | TP_fast_assign( | ||
792 | LOCAL_ASSIGN; | ||
793 | __entry->timestamp = ch_switch->timestamp; | ||
794 | __entry->block_tx = ch_switch->block_tx; | ||
795 | __entry->freq = ch_switch->channel->center_freq; | ||
796 | __entry->count = ch_switch->count; | ||
797 | ), | ||
798 | |||
799 | TP_printk( | ||
800 | LOCAL_PR_FMT " new freq:%u count:%d", | ||
801 | LOCAL_PR_ARG, __entry->freq, __entry->count | ||
802 | ) | ||
803 | ); | ||
804 | |||
777 | /* | 805 | /* |
778 | * Tracing for API calls that drivers call. | 806 | * Tracing for API calls that drivers call. |
779 | */ | 807 | */ |
@@ -992,6 +1020,27 @@ TRACE_EVENT(api_sta_block_awake, | |||
992 | ) | 1020 | ) |
993 | ); | 1021 | ); |
994 | 1022 | ||
1023 | TRACE_EVENT(api_chswitch_done, | ||
1024 | TP_PROTO(struct ieee80211_sub_if_data *sdata, bool success), | ||
1025 | |||
1026 | TP_ARGS(sdata, success), | ||
1027 | |||
1028 | TP_STRUCT__entry( | ||
1029 | VIF_ENTRY | ||
1030 | __field(bool, success) | ||
1031 | ), | ||
1032 | |||
1033 | TP_fast_assign( | ||
1034 | VIF_ASSIGN; | ||
1035 | __entry->success = success; | ||
1036 | ), | ||
1037 | |||
1038 | TP_printk( | ||
1039 | VIF_PR_FMT " success=%d", | ||
1040 | VIF_PR_ARG, __entry->success | ||
1041 | ) | ||
1042 | ); | ||
1043 | |||
995 | /* | 1044 | /* |
996 | * Tracing for internal functions | 1045 | * Tracing for internal functions |
997 | * (which may also be called in response to driver calls) | 1046 | * (which may also be called in response to driver calls) |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 7ef7798d04cd..1a9e2da37a93 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -998,7 +998,8 @@ int ieee80211_max_network_latency(struct notifier_block *nb, | |||
998 | unsigned long data, void *dummy); | 998 | unsigned long data, void *dummy); |
999 | void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 999 | void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
1000 | struct ieee80211_channel_sw_ie *sw_elem, | 1000 | struct ieee80211_channel_sw_ie *sw_elem, |
1001 | struct ieee80211_bss *bss); | 1001 | struct ieee80211_bss *bss, |
1002 | u64 timestamp); | ||
1002 | void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata); | 1003 | void ieee80211_sta_quiesce(struct ieee80211_sub_if_data *sdata); |
1003 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); | 1004 | void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata); |
1004 | 1005 | ||
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 3093e46273c3..c6c1f49cc456 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c | |||
@@ -342,7 +342,11 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
342 | goto out; | 342 | goto out; |
343 | 343 | ||
344 | sdata->local->oper_channel = sdata->local->csa_channel; | 344 | sdata->local->oper_channel = sdata->local->csa_channel; |
345 | ieee80211_hw_config(sdata->local, IEEE80211_CONF_CHANGE_CHANNEL); | 345 | if (!sdata->local->ops->channel_switch) { |
346 | /* call "hw_config" only if doing sw channel switch */ | ||
347 | ieee80211_hw_config(sdata->local, | ||
348 | IEEE80211_CONF_CHANGE_CHANNEL); | ||
349 | } | ||
346 | 350 | ||
347 | /* XXX: shouldn't really modify cfg80211-owned data! */ | 351 | /* XXX: shouldn't really modify cfg80211-owned data! */ |
348 | ifmgd->associated->channel = sdata->local->oper_channel; | 352 | ifmgd->associated->channel = sdata->local->oper_channel; |
@@ -354,6 +358,29 @@ static void ieee80211_chswitch_work(struct work_struct *work) | |||
354 | mutex_unlock(&ifmgd->mtx); | 358 | mutex_unlock(&ifmgd->mtx); |
355 | } | 359 | } |
356 | 360 | ||
361 | void ieee80211_chswitch_done(struct ieee80211_vif *vif, bool success) | ||
362 | { | ||
363 | struct ieee80211_sub_if_data *sdata; | ||
364 | struct ieee80211_if_managed *ifmgd; | ||
365 | |||
366 | sdata = vif_to_sdata(vif); | ||
367 | ifmgd = &sdata->u.mgd; | ||
368 | |||
369 | trace_api_chswitch_done(sdata, success); | ||
370 | if (!success) { | ||
371 | /* | ||
372 | * If the channel switch was not successful, stay | ||
373 | * around on the old channel. We currently lack | ||
374 | * good handling of this situation, possibly we | ||
375 | * should just drop the association. | ||
376 | */ | ||
377 | sdata->local->csa_channel = sdata->local->oper_channel; | ||
378 | } | ||
379 | |||
380 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); | ||
381 | } | ||
382 | EXPORT_SYMBOL(ieee80211_chswitch_done); | ||
383 | |||
357 | static void ieee80211_chswitch_timer(unsigned long data) | 384 | static void ieee80211_chswitch_timer(unsigned long data) |
358 | { | 385 | { |
359 | struct ieee80211_sub_if_data *sdata = | 386 | struct ieee80211_sub_if_data *sdata = |
@@ -370,7 +397,8 @@ static void ieee80211_chswitch_timer(unsigned long data) | |||
370 | 397 | ||
371 | void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | 398 | void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, |
372 | struct ieee80211_channel_sw_ie *sw_elem, | 399 | struct ieee80211_channel_sw_ie *sw_elem, |
373 | struct ieee80211_bss *bss) | 400 | struct ieee80211_bss *bss, |
401 | u64 timestamp) | ||
374 | { | 402 | { |
375 | struct cfg80211_bss *cbss = | 403 | struct cfg80211_bss *cbss = |
376 | container_of((void *)bss, struct cfg80211_bss, priv); | 404 | container_of((void *)bss, struct cfg80211_bss, priv); |
@@ -398,10 +426,29 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, | |||
398 | 426 | ||
399 | sdata->local->csa_channel = new_ch; | 427 | sdata->local->csa_channel = new_ch; |
400 | 428 | ||
429 | if (sdata->local->ops->channel_switch) { | ||
430 | /* use driver's channel switch callback */ | ||
431 | struct ieee80211_channel_switch ch_switch; | ||
432 | memset(&ch_switch, 0, sizeof(ch_switch)); | ||
433 | ch_switch.timestamp = timestamp; | ||
434 | if (sw_elem->mode) { | ||
435 | ch_switch.block_tx = true; | ||
436 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | ||
437 | IEEE80211_QUEUE_STOP_REASON_CSA); | ||
438 | } | ||
439 | ch_switch.channel = new_ch; | ||
440 | ch_switch.count = sw_elem->count; | ||
441 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | ||
442 | drv_channel_switch(sdata->local, &ch_switch); | ||
443 | return; | ||
444 | } | ||
445 | |||
446 | /* channel switch handled in software */ | ||
401 | if (sw_elem->count <= 1) { | 447 | if (sw_elem->count <= 1) { |
402 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); | 448 | ieee80211_queue_work(&sdata->local->hw, &ifmgd->chswitch_work); |
403 | } else { | 449 | } else { |
404 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | 450 | if (sw_elem->mode) |
451 | ieee80211_stop_queues_by_reason(&sdata->local->hw, | ||
405 | IEEE80211_QUEUE_STOP_REASON_CSA); | 452 | IEEE80211_QUEUE_STOP_REASON_CSA); |
406 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; | 453 | ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED; |
407 | mod_timer(&ifmgd->chswitch_timer, | 454 | mod_timer(&ifmgd->chswitch_timer, |
@@ -1317,7 +1364,8 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, | |||
1317 | ETH_ALEN) == 0)) { | 1364 | ETH_ALEN) == 0)) { |
1318 | struct ieee80211_channel_sw_ie *sw_elem = | 1365 | struct ieee80211_channel_sw_ie *sw_elem = |
1319 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; | 1366 | (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem; |
1320 | ieee80211_sta_process_chanswitch(sdata, sw_elem, bss); | 1367 | ieee80211_sta_process_chanswitch(sdata, sw_elem, |
1368 | bss, rx_status->mactime); | ||
1321 | } | 1369 | } |
1322 | } | 1370 | } |
1323 | 1371 | ||
@@ -1649,7 +1697,8 @@ static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, | |||
1649 | 1697 | ||
1650 | ieee80211_sta_process_chanswitch(sdata, | 1698 | ieee80211_sta_process_chanswitch(sdata, |
1651 | &mgmt->u.action.u.chan_switch.sw_elem, | 1699 | &mgmt->u.action.u.chan_switch.sw_elem, |
1652 | (void *)ifmgd->associated->priv); | 1700 | (void *)ifmgd->associated->priv, |
1701 | rx_status->mactime); | ||
1653 | break; | 1702 | break; |
1654 | } | 1703 | } |
1655 | mutex_unlock(&ifmgd->mtx); | 1704 | mutex_unlock(&ifmgd->mtx); |
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9a08f2c446c6..6e2a7bcd8cb8 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c | |||
@@ -1253,6 +1253,12 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) | |||
1253 | if (skb_linearize(rx->skb)) | 1253 | if (skb_linearize(rx->skb)) |
1254 | return RX_DROP_UNUSABLE; | 1254 | return RX_DROP_UNUSABLE; |
1255 | 1255 | ||
1256 | /* | ||
1257 | * skb_linearize() might change the skb->data and | ||
1258 | * previously cached variables (in this case, hdr) need to | ||
1259 | * be refreshed with the new data. | ||
1260 | */ | ||
1261 | hdr = (struct ieee80211_hdr *)rx->skb->data; | ||
1256 | seq = (sc & IEEE80211_SCTL_SEQ) >> 4; | 1262 | seq = (sc & IEEE80211_SCTL_SEQ) >> 4; |
1257 | 1263 | ||
1258 | if (frag == 0) { | 1264 | if (frag == 0) { |
diff --git a/net/mac80211/work.c b/net/mac80211/work.c index 3dd07600199d..be3d4a698692 100644 --- a/net/mac80211/work.c +++ b/net/mac80211/work.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #define IEEE80211_MAX_PROBE_TRIES 5 | 33 | #define IEEE80211_MAX_PROBE_TRIES 5 |
34 | 34 | ||
35 | enum work_action { | 35 | enum work_action { |
36 | WORK_ACT_MISMATCH, | ||
36 | WORK_ACT_NONE, | 37 | WORK_ACT_NONE, |
37 | WORK_ACT_TIMEOUT, | 38 | WORK_ACT_TIMEOUT, |
38 | WORK_ACT_DONE, | 39 | WORK_ACT_DONE, |
@@ -585,7 +586,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_work *wk, | |||
585 | u16 auth_alg, auth_transaction, status_code; | 586 | u16 auth_alg, auth_transaction, status_code; |
586 | 587 | ||
587 | if (wk->type != IEEE80211_WORK_AUTH) | 588 | if (wk->type != IEEE80211_WORK_AUTH) |
588 | return WORK_ACT_NONE; | 589 | return WORK_ACT_MISMATCH; |
589 | 590 | ||
590 | if (len < 24 + 6) | 591 | if (len < 24 + 6) |
591 | return WORK_ACT_NONE; | 592 | return WORK_ACT_NONE; |
@@ -636,6 +637,9 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_work *wk, | |||
636 | struct ieee802_11_elems elems; | 637 | struct ieee802_11_elems elems; |
637 | u8 *pos; | 638 | u8 *pos; |
638 | 639 | ||
640 | if (wk->type != IEEE80211_WORK_ASSOC) | ||
641 | return WORK_ACT_MISMATCH; | ||
642 | |||
639 | /* | 643 | /* |
640 | * AssocResp and ReassocResp have identical structure, so process both | 644 | * AssocResp and ReassocResp have identical structure, so process both |
641 | * of them in this function. | 645 | * of them in this function. |
@@ -691,6 +695,12 @@ ieee80211_rx_mgmt_probe_resp(struct ieee80211_work *wk, | |||
691 | 695 | ||
692 | ASSERT_WORK_MTX(local); | 696 | ASSERT_WORK_MTX(local); |
693 | 697 | ||
698 | if (wk->type != IEEE80211_WORK_DIRECT_PROBE) | ||
699 | return WORK_ACT_MISMATCH; | ||
700 | |||
701 | if (len < 24 + 12) | ||
702 | return WORK_ACT_NONE; | ||
703 | |||
694 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; | 704 | baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt; |
695 | if (baselen > len) | 705 | if (baselen > len) |
696 | return WORK_ACT_NONE; | 706 | return WORK_ACT_NONE; |
@@ -705,7 +715,7 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local, | |||
705 | struct ieee80211_rx_status *rx_status; | 715 | struct ieee80211_rx_status *rx_status; |
706 | struct ieee80211_mgmt *mgmt; | 716 | struct ieee80211_mgmt *mgmt; |
707 | struct ieee80211_work *wk; | 717 | struct ieee80211_work *wk; |
708 | enum work_action rma = WORK_ACT_NONE; | 718 | enum work_action rma; |
709 | u16 fc; | 719 | u16 fc; |
710 | 720 | ||
711 | rx_status = (struct ieee80211_rx_status *) skb->cb; | 721 | rx_status = (struct ieee80211_rx_status *) skb->cb; |
@@ -752,7 +762,17 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local, | |||
752 | break; | 762 | break; |
753 | default: | 763 | default: |
754 | WARN_ON(1); | 764 | WARN_ON(1); |
765 | rma = WORK_ACT_NONE; | ||
755 | } | 766 | } |
767 | |||
768 | /* | ||
769 | * We've either received an unexpected frame, or we have | ||
770 | * multiple work items and need to match the frame to the | ||
771 | * right one. | ||
772 | */ | ||
773 | if (rma == WORK_ACT_MISMATCH) | ||
774 | continue; | ||
775 | |||
756 | /* | 776 | /* |
757 | * We've processed this frame for that work, so it can't | 777 | * We've processed this frame for that work, so it can't |
758 | * belong to another work struct. | 778 | * belong to another work struct. |
@@ -762,6 +782,9 @@ static void ieee80211_work_rx_queued_mgmt(struct ieee80211_local *local, | |||
762 | } | 782 | } |
763 | 783 | ||
764 | switch (rma) { | 784 | switch (rma) { |
785 | case WORK_ACT_MISMATCH: | ||
786 | /* ignore this unmatched frame */ | ||
787 | break; | ||
765 | case WORK_ACT_NONE: | 788 | case WORK_ACT_NONE: |
766 | break; | 789 | break; |
767 | case WORK_ACT_DONE: | 790 | case WORK_ACT_DONE: |