aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/tx.c
diff options
context:
space:
mode:
authorMarco Porsch <marco@cozybit.com>2013-01-30 12:14:08 -0500
committerJohannes Berg <johannes.berg@intel.com>2013-02-04 12:57:47 -0500
commit3f52b7e328c526fa7a592af9bf5772c591ed38a4 (patch)
tree1bcf93b87c99c3be6c9020a41b28114130f4c251 /net/mac80211/tx.c
parent0532d4f154b87da6361ab90d12f35142d5119dc1 (diff)
mac80211: mesh power save basics
Add routines to - maintain a PS mode for each peer and a non-peer PS mode - indicate own PS mode in transmitted frames - track neighbor STAs power modes - buffer frames when neighbors are in PS mode - add TIM and Awake Window IE to beacons - release frames in Mesh Peer Service Periods Add local_pm to sta_info to represent the link-specific power mode at this station towards the remote station. When a peer link is established, use the default power mode stored in mesh config. Update the PS status if the peering status of a neighbor changes. Maintain a mesh power mode for non-peer mesh STAs. Set the non-peer power mode to active mode during peering. Authenticated mesh peering is currently not working when either node is configured to be in power save mode. Indicate the current power mode in transmitted frames. Use QoS Nulls to indicate mesh power mode transitions. For performance reasons, calls to the function setting the frame flags are placed in HWMP routing routines, as there the STA pointer is already available. Add peer_pm to sta_info to represent the peer's link-specific power mode towards the local station. Add nonpeer_pm to represent the peer's power mode towards all non-peer stations. Track power modes based on received frames. Add the ps_data structure to ieee80211_if_mesh (for TIM map, PS neighbor counter and group-addressed frame buffer). Set WLAN_STA_PS flag for STA in PS mode to use the unicast frame buffering routines in the tx path. Update num_sta_ps to buffer and release group-addressed frames after DTIM beacons. Announce the awake window duration in beacons if in light or deep sleep mode towards any peer or non-peer. Create a TIM IE similarly to AP mode and add it to mesh beacons. Parse received Awake Window IEs and check TIM IEs for buffered frames. Release frames towards peers in mesh Peer Service Periods. Use the corresponding trigger frames and monitor the MPSP status. Append a QoS Null as trigger frame if neccessary to properly end the MPSP. Currently, in HT channels MPSPs behave imperfectly and show large delay spikes and frame losses. Signed-off-by: Marco Porsch <marco@cozybit.com> Signed-off-by: Ivan Bezyazychnyy <ivan.bezyazychnyy@gmail.com> Signed-off-by: Mike Krinkin <krinkin.m.u@gmail.com> Signed-off-by: Max Filippov <jcmvbkbc@gmail.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r--net/mac80211/tx.c31
1 files changed, 22 insertions, 9 deletions
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 7892b0a8873e..2ef0e19b06bb 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -329,6 +329,8 @@ static void purge_old_ps_buffers(struct ieee80211_local *local)
329 329
330 if (sdata->vif.type == NL80211_IFTYPE_AP) 330 if (sdata->vif.type == NL80211_IFTYPE_AP)
331 ps = &sdata->u.ap.ps; 331 ps = &sdata->u.ap.ps;
332 else if (ieee80211_vif_is_mesh(&sdata->vif))
333 ps = &sdata->u.mesh.ps;
332 else 334 else
333 continue; 335 continue;
334 336
@@ -372,18 +374,20 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
372 /* 374 /*
373 * broadcast/multicast frame 375 * broadcast/multicast frame
374 * 376 *
375 * If any of the associated stations is in power save mode, 377 * If any of the associated/peer stations is in power save mode,
376 * the frame is buffered to be sent after DTIM beacon frame. 378 * the frame is buffered to be sent after DTIM beacon frame.
377 * This is done either by the hardware or us. 379 * This is done either by the hardware or us.
378 */ 380 */
379 381
380 /* powersaving STAs currently only in AP/VLAN mode */ 382 /* powersaving STAs currently only in AP/VLAN/mesh mode */
381 if (tx->sdata->vif.type == NL80211_IFTYPE_AP || 383 if (tx->sdata->vif.type == NL80211_IFTYPE_AP ||
382 tx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { 384 tx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
383 if (!tx->sdata->bss) 385 if (!tx->sdata->bss)
384 return TX_CONTINUE; 386 return TX_CONTINUE;
385 387
386 ps = &tx->sdata->bss->ps; 388 ps = &tx->sdata->bss->ps;
389 } else if (ieee80211_vif_is_mesh(&tx->sdata->vif)) {
390 ps = &tx->sdata->u.mesh.ps;
387 } else { 391 } else {
388 return TX_CONTINUE; 392 return TX_CONTINUE;
389 } 393 }
@@ -1473,12 +1477,14 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
1473 hdr = (struct ieee80211_hdr *) skb->data; 1477 hdr = (struct ieee80211_hdr *) skb->data;
1474 info->control.vif = &sdata->vif; 1478 info->control.vif = &sdata->vif;
1475 1479
1476 if (ieee80211_vif_is_mesh(&sdata->vif) && 1480 if (ieee80211_vif_is_mesh(&sdata->vif)) {
1477 ieee80211_is_data(hdr->frame_control) && 1481 if (ieee80211_is_data(hdr->frame_control) &&
1478 !is_multicast_ether_addr(hdr->addr1) && 1482 is_unicast_ether_addr(hdr->addr1)) {
1479 mesh_nexthop_resolve(skb, sdata)) { 1483 if (mesh_nexthop_resolve(skb, sdata))
1480 /* skb queued: don't free */ 1484 return; /* skb queued: don't free */
1481 return; 1485 } else {
1486 ieee80211_mps_set_frame_flags(sdata, NULL, hdr);
1487 }
1482 } 1488 }
1483 1489
1484 ieee80211_set_qos_hdr(sdata, skb); 1490 ieee80211_set_qos_hdr(sdata, skb);
@@ -2445,12 +2451,14 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2445 2 + /* NULL SSID */ 2451 2 + /* NULL SSID */
2446 2 + 8 + /* supported rates */ 2452 2 + 8 + /* supported rates */
2447 2 + 3 + /* DS params */ 2453 2 + 3 + /* DS params */
2454 256 + /* TIM IE */
2448 2 + (IEEE80211_MAX_SUPP_RATES - 8) + 2455 2 + (IEEE80211_MAX_SUPP_RATES - 8) +
2449 2 + sizeof(struct ieee80211_ht_cap) + 2456 2 + sizeof(struct ieee80211_ht_cap) +
2450 2 + sizeof(struct ieee80211_ht_operation) + 2457 2 + sizeof(struct ieee80211_ht_operation) +
2451 2 + sdata->u.mesh.mesh_id_len + 2458 2 + sdata->u.mesh.mesh_id_len +
2452 2 + sizeof(struct ieee80211_meshconf_ie) + 2459 2 + sizeof(struct ieee80211_meshconf_ie) +
2453 sdata->u.mesh.ie_len); 2460 sdata->u.mesh.ie_len +
2461 2 + sizeof(__le16)); /* awake window */
2454 if (!skb) 2462 if (!skb)
2455 goto out; 2463 goto out;
2456 2464
@@ -2462,6 +2470,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2462 eth_broadcast_addr(mgmt->da); 2470 eth_broadcast_addr(mgmt->da);
2463 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN); 2471 memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
2464 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN); 2472 memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
2473 ieee80211_mps_set_frame_flags(sdata, NULL, (void *) mgmt);
2465 mgmt->u.beacon.beacon_int = 2474 mgmt->u.beacon.beacon_int =
2466 cpu_to_le16(sdata->vif.bss_conf.beacon_int); 2475 cpu_to_le16(sdata->vif.bss_conf.beacon_int);
2467 mgmt->u.beacon.capab_info |= cpu_to_le16( 2476 mgmt->u.beacon.capab_info |= cpu_to_le16(
@@ -2475,12 +2484,14 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
2475 2484
2476 if (ieee80211_add_srates_ie(sdata, skb, true, band) || 2485 if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
2477 mesh_add_ds_params_ie(skb, sdata) || 2486 mesh_add_ds_params_ie(skb, sdata) ||
2487 ieee80211_beacon_add_tim(sdata, &ifmsh->ps, skb) ||
2478 ieee80211_add_ext_srates_ie(sdata, skb, true, band) || 2488 ieee80211_add_ext_srates_ie(sdata, skb, true, band) ||
2479 mesh_add_rsn_ie(skb, sdata) || 2489 mesh_add_rsn_ie(skb, sdata) ||
2480 mesh_add_ht_cap_ie(skb, sdata) || 2490 mesh_add_ht_cap_ie(skb, sdata) ||
2481 mesh_add_ht_oper_ie(skb, sdata) || 2491 mesh_add_ht_oper_ie(skb, sdata) ||
2482 mesh_add_meshid_ie(skb, sdata) || 2492 mesh_add_meshid_ie(skb, sdata) ||
2483 mesh_add_meshconf_ie(skb, sdata) || 2493 mesh_add_meshconf_ie(skb, sdata) ||
2494 mesh_add_awake_window_ie(skb, sdata) ||
2484 mesh_add_vendor_ies(skb, sdata)) { 2495 mesh_add_vendor_ies(skb, sdata)) {
2485 pr_err("o11s: couldn't add ies!\n"); 2496 pr_err("o11s: couldn't add ies!\n");
2486 goto out; 2497 goto out;
@@ -2734,6 +2745,8 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
2734 goto out; 2745 goto out;
2735 2746
2736 ps = &sdata->u.ap.ps; 2747 ps = &sdata->u.ap.ps;
2748 } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
2749 ps = &sdata->u.mesh.ps;
2737 } else { 2750 } else {
2738 goto out; 2751 goto out;
2739 } 2752 }