aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mlme.c
diff options
context:
space:
mode:
authorKalle Valo <kalle.valo@nokia.com>2010-01-12 03:42:31 -0500
committerJohn W. Linville <linville@tuxdriver.com>2010-01-12 14:20:58 -0500
commitab13315af97919fae0e014748105fdc2e30afb2d (patch)
treebefa549272ecff20b2839bd6671e4cccbce448f9 /net/mac80211/mlme.c
parent2d46d7c121436f1dafe91b0a8d9b99e534cfa5f8 (diff)
mac80211: add U-APSD client support
Add Unscheduled Automatic Power-Save Delivery (U-APSD) client support. The idea is that the data frames from the client trigger AP to send the buffered frames with ACs which have U-APSD enabled. This decreases latency and makes it possible to save even more power. Driver needs to use IEEE80211_HW_UAPSD to enable the feature. The current implementation assumes that firmware takes care of the wakeup and hardware needing IEEE80211_HW_PS_NULLFUNC_STACK is not yet supported. Tested with wl1251 on a Nokia N900 and Cisco Aironet 1231G AP and running various test traffic with ping. Signed-off-by: Kalle Valo <kalle.valo@nokia.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211/mlme.c')
-rw-r--r--net/mac80211/mlme.c31
1 files changed, 28 insertions, 3 deletions
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 86f025bc9456..39c27d83a4f2 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -569,7 +569,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
569 struct ieee80211_tx_queue_params params; 569 struct ieee80211_tx_queue_params params;
570 size_t left; 570 size_t left;
571 int count; 571 int count;
572 u8 *pos; 572 u8 *pos, uapsd_queues = 0;
573 573
574 if (local->hw.queues < 4) 574 if (local->hw.queues < 4)
575 return; 575 return;
@@ -579,6 +579,10 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
579 579
580 if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) 580 if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
581 return; 581 return;
582
583 if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED)
584 uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES;
585
582 count = wmm_param[6] & 0x0f; 586 count = wmm_param[6] & 0x0f;
583 if (count == ifmgd->wmm_last_param_set) 587 if (count == ifmgd->wmm_last_param_set)
584 return; 588 return;
@@ -593,6 +597,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
593 for (; left >= 4; left -= 4, pos += 4) { 597 for (; left >= 4; left -= 4, pos += 4) {
594 int aci = (pos[0] >> 5) & 0x03; 598 int aci = (pos[0] >> 5) & 0x03;
595 int acm = (pos[0] >> 4) & 0x01; 599 int acm = (pos[0] >> 4) & 0x01;
600 bool uapsd = false;
596 int queue; 601 int queue;
597 602
598 switch (aci) { 603 switch (aci) {
@@ -600,22 +605,30 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
600 queue = 3; 605 queue = 3;
601 if (acm) 606 if (acm)
602 local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ 607 local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */
608 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK)
609 uapsd = true;
603 break; 610 break;
604 case 2: /* AC_VI */ 611 case 2: /* AC_VI */
605 queue = 1; 612 queue = 1;
606 if (acm) 613 if (acm)
607 local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ 614 local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
615 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI)
616 uapsd = true;
608 break; 617 break;
609 case 3: /* AC_VO */ 618 case 3: /* AC_VO */
610 queue = 0; 619 queue = 0;
611 if (acm) 620 if (acm)
612 local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ 621 local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
622 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO)
623 uapsd = true;
613 break; 624 break;
614 case 0: /* AC_BE */ 625 case 0: /* AC_BE */
615 default: 626 default:
616 queue = 2; 627 queue = 2;
617 if (acm) 628 if (acm)
618 local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ 629 local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
630 if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE)
631 uapsd = true;
619 break; 632 break;
620 } 633 }
621 634
@@ -623,11 +636,14 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
623 params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4); 636 params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
624 params.cw_min = ecw2cw(pos[1] & 0x0f); 637 params.cw_min = ecw2cw(pos[1] & 0x0f);
625 params.txop = get_unaligned_le16(pos + 2); 638 params.txop = get_unaligned_le16(pos + 2);
639 params.uapsd = uapsd;
640
626#ifdef CONFIG_MAC80211_VERBOSE_DEBUG 641#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
627 printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d " 642 printk(KERN_DEBUG "%s: WMM queue=%d aci=%d acm=%d aifs=%d "
628 "cWmin=%d cWmax=%d txop=%d\n", 643 "cWmin=%d cWmax=%d txop=%d uapsd=%d\n",
629 wiphy_name(local->hw.wiphy), queue, aci, acm, 644 wiphy_name(local->hw.wiphy), queue, aci, acm,
630 params.aifs, params.cw_min, params.cw_max, params.txop); 645 params.aifs, params.cw_min, params.cw_max, params.txop,
646 params.uapsd);
631#endif 647#endif
632 if (drv_conf_tx(local, queue, &params) && local->ops->conf_tx) 648 if (drv_conf_tx(local, queue, &params) && local->ops->conf_tx)
633 printk(KERN_DEBUG "%s: failed to set TX queue " 649 printk(KERN_DEBUG "%s: failed to set TX queue "
@@ -1906,6 +1922,15 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
1906 wk->assoc.ht_information_ie = 1922 wk->assoc.ht_information_ie =
1907 ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION); 1923 ieee80211_bss_get_ie(req->bss, WLAN_EID_HT_INFORMATION);
1908 1924
1925 if (bss->wmm_used && bss->uapsd_supported &&
1926 (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
1927 wk->assoc.uapsd_used = true;
1928 ifmgd->flags |= IEEE80211_STA_UAPSD_ENABLED;
1929 } else {
1930 wk->assoc.uapsd_used = false;
1931 ifmgd->flags &= ~IEEE80211_STA_UAPSD_ENABLED;
1932 }
1933
1909 ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID); 1934 ssid = ieee80211_bss_get_ie(req->bss, WLAN_EID_SSID);
1910 memcpy(wk->assoc.ssid, ssid + 2, ssid[1]); 1935 memcpy(wk->assoc.ssid, ssid + 2, ssid[1]);
1911 wk->assoc.ssid_len = ssid[1]; 1936 wk->assoc.ssid_len = ssid[1];