1 /*- 2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 __FBSDID("$FreeBSD$"); 28 29 /* 30 * IEEE 802.11 power save support. 31 */ 32 #include "opt_wlan.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 38 #include <sys/socket.h> 39 40 #include <net/if.h> 41 #include <net/if_var.h> 42 #include <net/if_media.h> 43 #include <net/ethernet.h> 44 45 #include <net80211/ieee80211_var.h> 46 47 #include <net/bpf.h> 48 49 static void ieee80211_update_ps(struct ieee80211vap *, int); 50 static int ieee80211_set_tim(struct ieee80211_node *, int); 51 52 static MALLOC_DEFINE(M_80211_POWER, "80211power", "802.11 power save state"); 53 54 void 55 ieee80211_power_attach(struct ieee80211com *ic) 56 { 57 } 58 59 void 60 ieee80211_power_detach(struct ieee80211com *ic) 61 { 62 } 63 64 void 65 ieee80211_power_vattach(struct ieee80211vap *vap) 66 { 67 if (vap->iv_opmode == IEEE80211_M_HOSTAP || 68 vap->iv_opmode == IEEE80211_M_IBSS) { 69 /* NB: driver should override */ 70 vap->iv_update_ps = ieee80211_update_ps; 71 vap->iv_set_tim = ieee80211_set_tim; 72 } 73 vap->iv_node_ps = ieee80211_node_pwrsave; 74 vap->iv_sta_ps = ieee80211_sta_pwrsave; 75 } 76 77 void 78 ieee80211_power_latevattach(struct ieee80211vap *vap) 79 { 80 /* 81 * Allocate these only if needed. Beware that we 82 * know adhoc mode doesn't support ATIM yet... 83 */ 84 if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 85 vap->iv_tim_len = howmany(vap->iv_max_aid,8) * sizeof(uint8_t); 86 vap->iv_tim_bitmap = (uint8_t *) IEEE80211_MALLOC(vap->iv_tim_len, 87 M_80211_POWER, 88 IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); 89 if (vap->iv_tim_bitmap == NULL) { 90 printf("%s: no memory for TIM bitmap!\n", __func__); 91 /* XXX good enough to keep from crashing? */ 92 vap->iv_tim_len = 0; 93 } 94 } 95 } 96 97 void 98 ieee80211_power_vdetach(struct ieee80211vap *vap) 99 { 100 if (vap->iv_tim_bitmap != NULL) { 101 IEEE80211_FREE(vap->iv_tim_bitmap, M_80211_POWER); 102 vap->iv_tim_bitmap = NULL; 103 } 104 } 105 106 void 107 ieee80211_psq_init(struct ieee80211_psq *psq, const char *name) 108 { 109 memset(psq, 0, sizeof(*psq)); 110 psq->psq_maxlen = IEEE80211_PS_MAX_QUEUE; 111 IEEE80211_PSQ_INIT(psq, name); /* OS-dependent setup */ 112 } 113 114 void 115 ieee80211_psq_cleanup(struct ieee80211_psq *psq) 116 { 117 #if 0 118 psq_drain(psq); /* XXX should not be needed? */ 119 #else 120 KASSERT(psq->psq_len == 0, ("%d frames on ps q", psq->psq_len)); 121 #endif 122 IEEE80211_PSQ_DESTROY(psq); /* OS-dependent cleanup */ 123 } 124 125 /* 126 * Return the highest priority frame in the ps queue. 127 */ 128 struct mbuf * 129 ieee80211_node_psq_dequeue(struct ieee80211_node *ni, int *qlen) 130 { 131 struct ieee80211_psq *psq = &ni->ni_psq; 132 struct ieee80211_psq_head *qhead; 133 struct mbuf *m; 134 135 IEEE80211_PSQ_LOCK(psq); 136 qhead = &psq->psq_head[0]; 137 again: 138 if ((m = qhead->head) != NULL) { 139 if ((qhead->head = m->m_nextpkt) == NULL) 140 qhead->tail = NULL; 141 KASSERT(qhead->len > 0, ("qhead len %d", qhead->len)); 142 qhead->len--; 143 KASSERT(psq->psq_len > 0, ("psq len %d", psq->psq_len)); 144 psq->psq_len--; 145 m->m_nextpkt = NULL; 146 } 147 if (m == NULL && qhead == &psq->psq_head[0]) { 148 /* Algol-68 style for loop */ 149 qhead = &psq->psq_head[1]; 150 goto again; 151 } 152 if (qlen != NULL) 153 *qlen = psq->psq_len; 154 IEEE80211_PSQ_UNLOCK(psq); 155 return m; 156 } 157 158 /* 159 * Reclaim an mbuf from the ps q. If marked with M_ENCAP 160 * we assume there is a node reference that must be relcaimed. 161 */ 162 static void 163 psq_mfree(struct mbuf *m) 164 { 165 if (m->m_flags & M_ENCAP) { 166 struct ieee80211_node *ni = (void *) m->m_pkthdr.rcvif; 167 ieee80211_free_node(ni); 168 } 169 m->m_nextpkt = NULL; 170 m_freem(m); 171 } 172 173 /* 174 * Clear any frames queued in the power save queue. 175 * The number of frames that were present is returned. 176 */ 177 static int 178 psq_drain(struct ieee80211_psq *psq) 179 { 180 struct ieee80211_psq_head *qhead; 181 struct mbuf *m; 182 int qlen; 183 184 IEEE80211_PSQ_LOCK(psq); 185 qlen = psq->psq_len; 186 qhead = &psq->psq_head[0]; 187 again: 188 while ((m = qhead->head) != NULL) { 189 qhead->head = m->m_nextpkt; 190 psq_mfree(m); 191 } 192 qhead->tail = NULL; 193 qhead->len = 0; 194 if (qhead == &psq->psq_head[0]) { /* Algol-68 style for loop */ 195 qhead = &psq->psq_head[1]; 196 goto again; 197 } 198 psq->psq_len = 0; 199 IEEE80211_PSQ_UNLOCK(psq); 200 201 return qlen; 202 } 203 204 /* 205 * Clear any frames queued in the power save queue. 206 * The number of frames that were present is returned. 207 */ 208 int 209 ieee80211_node_psq_drain(struct ieee80211_node *ni) 210 { 211 return psq_drain(&ni->ni_psq); 212 } 213 214 /* 215 * Age frames on the power save queue. The aging interval is 216 * 4 times the listen interval specified by the station. This 217 * number is factored into the age calculations when the frame 218 * is placed on the queue. We store ages as time differences 219 * so we can check and/or adjust only the head of the list. 220 * If a frame's age exceeds the threshold then discard it. 221 * The number of frames discarded is returned so the caller 222 * can check if it needs to adjust the tim. 223 */ 224 int 225 ieee80211_node_psq_age(struct ieee80211_node *ni) 226 { 227 struct ieee80211_psq *psq = &ni->ni_psq; 228 int discard = 0; 229 230 if (psq->psq_len != 0) { 231 #ifdef IEEE80211_DEBUG 232 struct ieee80211vap *vap = ni->ni_vap; 233 #endif 234 struct ieee80211_psq_head *qhead; 235 struct mbuf *m; 236 237 IEEE80211_PSQ_LOCK(psq); 238 qhead = &psq->psq_head[0]; 239 again: 240 while ((m = qhead->head) != NULL && 241 M_AGE_GET(m) < IEEE80211_INACT_WAIT) { 242 IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 243 "discard frame, age %u", M_AGE_GET(m)); 244 if ((qhead->head = m->m_nextpkt) == NULL) 245 qhead->tail = NULL; 246 KASSERT(qhead->len > 0, ("qhead len %d", qhead->len)); 247 qhead->len--; 248 KASSERT(psq->psq_len > 0, ("psq len %d", psq->psq_len)); 249 psq->psq_len--; 250 psq_mfree(m); 251 discard++; 252 } 253 if (qhead == &psq->psq_head[0]) { /* Algol-68 style for loop */ 254 qhead = &psq->psq_head[1]; 255 goto again; 256 } 257 if (m != NULL) 258 M_AGE_SUB(m, IEEE80211_INACT_WAIT); 259 IEEE80211_PSQ_UNLOCK(psq); 260 261 IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 262 "discard %u frames for age", discard); 263 IEEE80211_NODE_STAT_ADD(ni, ps_discard, discard); 264 } 265 return discard; 266 } 267 268 /* 269 * Handle a change in the PS station occupancy. 270 */ 271 static void 272 ieee80211_update_ps(struct ieee80211vap *vap, int nsta) 273 { 274 275 KASSERT(vap->iv_opmode == IEEE80211_M_HOSTAP || 276 vap->iv_opmode == IEEE80211_M_IBSS, 277 ("operating mode %u", vap->iv_opmode)); 278 } 279 280 /* 281 * Indicate whether there are frames queued for a station in power-save mode. 282 */ 283 static int 284 ieee80211_set_tim(struct ieee80211_node *ni, int set) 285 { 286 struct ieee80211vap *vap = ni->ni_vap; 287 struct ieee80211com *ic = ni->ni_ic; 288 uint16_t aid; 289 int changed; 290 291 KASSERT(vap->iv_opmode == IEEE80211_M_HOSTAP || 292 vap->iv_opmode == IEEE80211_M_IBSS, 293 ("operating mode %u", vap->iv_opmode)); 294 295 aid = IEEE80211_AID(ni->ni_associd); 296 KASSERT(aid < vap->iv_max_aid, 297 ("bogus aid %u, max %u", aid, vap->iv_max_aid)); 298 299 IEEE80211_LOCK(ic); 300 changed = (set != (isset(vap->iv_tim_bitmap, aid) != 0)); 301 if (changed) { 302 if (set) { 303 setbit(vap->iv_tim_bitmap, aid); 304 vap->iv_ps_pending++; 305 } else { 306 clrbit(vap->iv_tim_bitmap, aid); 307 vap->iv_ps_pending--; 308 } 309 /* NB: we know vap is in RUN state so no need to check */ 310 vap->iv_update_beacon(vap, IEEE80211_BEACON_TIM); 311 } 312 IEEE80211_UNLOCK(ic); 313 314 return changed; 315 } 316 317 /* 318 * Save an outbound packet for a node in power-save sleep state. 319 * The new packet is placed on the node's saved queue, and the TIM 320 * is changed, if necessary. 321 */ 322 int 323 ieee80211_pwrsave(struct ieee80211_node *ni, struct mbuf *m) 324 { 325 struct ieee80211_psq *psq = &ni->ni_psq; 326 struct ieee80211vap *vap = ni->ni_vap; 327 struct ieee80211com *ic = ni->ni_ic; 328 struct ieee80211_psq_head *qhead; 329 int qlen, age; 330 331 IEEE80211_PSQ_LOCK(psq); 332 if (psq->psq_len >= psq->psq_maxlen) { 333 psq->psq_drops++; 334 IEEE80211_PSQ_UNLOCK(psq); 335 IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni, 336 "pwr save q overflow, drops %d (size %d)", 337 psq->psq_drops, psq->psq_len); 338 #ifdef IEEE80211_DEBUG 339 if (ieee80211_msg_dumppkts(vap)) 340 ieee80211_dump_pkt(ni->ni_ic, mtod(m, caddr_t), 341 m->m_len, -1, -1); 342 #endif 343 psq_mfree(m); 344 return ENOSPC; 345 } 346 /* 347 * Tag the frame with it's expiry time and insert it in 348 * the appropriate queue. The aging interval is 4 times 349 * the listen interval specified by the station. Frames 350 * that sit around too long are reclaimed using this 351 * information. 352 */ 353 /* TU -> secs. XXX handle overflow? */ 354 age = IEEE80211_TU_TO_MS((ni->ni_intval * ic->ic_bintval) << 2) / 1000; 355 /* 356 * Encapsulated frames go on the high priority queue, 357 * other stuff goes on the low priority queue. We use 358 * this to order frames returned out of the driver 359 * ahead of frames we collect in ieee80211_start. 360 */ 361 if (m->m_flags & M_ENCAP) 362 qhead = &psq->psq_head[0]; 363 else 364 qhead = &psq->psq_head[1]; 365 if (qhead->tail == NULL) { 366 struct mbuf *mh; 367 368 qhead->head = m; 369 /* 370 * Take care to adjust age when inserting the first 371 * frame of a queue and the other queue already has 372 * frames. We need to preserve the age difference 373 * relationship so ieee80211_node_psq_age works. 374 */ 375 if (qhead == &psq->psq_head[1]) { 376 mh = psq->psq_head[0].head; 377 if (mh != NULL) 378 age-= M_AGE_GET(mh); 379 } else { 380 mh = psq->psq_head[1].head; 381 if (mh != NULL) { 382 int nage = M_AGE_GET(mh) - age; 383 /* XXX is clamping to zero good 'nuf? */ 384 M_AGE_SET(mh, nage < 0 ? 0 : nage); 385 } 386 } 387 } else { 388 qhead->tail->m_nextpkt = m; 389 age -= M_AGE_GET(qhead->head); 390 } 391 KASSERT(age >= 0, ("age %d", age)); 392 M_AGE_SET(m, age); 393 m->m_nextpkt = NULL; 394 qhead->tail = m; 395 qhead->len++; 396 qlen = ++(psq->psq_len); 397 IEEE80211_PSQ_UNLOCK(psq); 398 399 IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 400 "save frame with age %d, %u now queued", age, qlen); 401 402 if (qlen == 1 && vap->iv_set_tim != NULL) 403 vap->iv_set_tim(ni, 1); 404 405 return 0; 406 } 407 408 /* 409 * Move frames from the ps q to the vap's send queue 410 * and/or the driver's send queue; and kick the start 411 * method for each, as appropriate. Note we're careful 412 * to preserve packet ordering here. 413 */ 414 static void 415 pwrsave_flushq(struct ieee80211_node *ni) 416 { 417 struct ieee80211_psq *psq = &ni->ni_psq; 418 struct ieee80211com *ic = ni->ni_ic; 419 struct ieee80211vap *vap = ni->ni_vap; 420 struct ieee80211_psq_head *qhead; 421 struct mbuf *parent_q = NULL, *ifp_q = NULL; 422 struct mbuf *m; 423 424 IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 425 "flush ps queue, %u packets queued", psq->psq_len); 426 427 IEEE80211_PSQ_LOCK(psq); 428 qhead = &psq->psq_head[0]; /* 802.11 frames */ 429 if (qhead->head != NULL) { 430 /* XXX could dispatch through vap and check M_ENCAP */ 431 /* XXX need different driver interface */ 432 /* XXX bypasses q max and OACTIVE */ 433 parent_q = qhead->head; 434 qhead->head = qhead->tail = NULL; 435 qhead->len = 0; 436 } 437 438 qhead = &psq->psq_head[1]; /* 802.3 frames */ 439 if (qhead->head != NULL) { 440 /* XXX need different driver interface */ 441 /* XXX bypasses q max and OACTIVE */ 442 ifp_q = qhead->head; 443 qhead->head = qhead->tail = NULL; 444 qhead->len = 0; 445 } 446 psq->psq_len = 0; 447 IEEE80211_PSQ_UNLOCK(psq); 448 449 /* NB: do this outside the psq lock */ 450 /* XXX packets might get reordered if parent is OACTIVE */ 451 /* parent frames, should be encapsulated */ 452 while (parent_q != NULL) { 453 m = parent_q; 454 parent_q = m->m_nextpkt; 455 m->m_nextpkt = NULL; 456 /* must be encapsulated */ 457 KASSERT((m->m_flags & M_ENCAP), 458 ("%s: parentq with non-M_ENCAP frame!\n", 459 __func__)); 460 (void) ieee80211_parent_xmitpkt(ic, m); 461 } 462 463 /* VAP frames, aren't encapsulated */ 464 while (ifp_q != NULL) { 465 m = ifp_q; 466 ifp_q = m->m_nextpkt; 467 m->m_nextpkt = NULL; 468 KASSERT((!(m->m_flags & M_ENCAP)), 469 ("%s: vapq with M_ENCAP frame!\n", __func__)); 470 (void) ieee80211_vap_xmitpkt(vap, m); 471 } 472 } 473 474 /* 475 * Handle station power-save state change. 476 */ 477 void 478 ieee80211_node_pwrsave(struct ieee80211_node *ni, int enable) 479 { 480 struct ieee80211vap *vap = ni->ni_vap; 481 int update; 482 483 update = 0; 484 if (enable) { 485 if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) { 486 vap->iv_ps_sta++; 487 update = 1; 488 } 489 ni->ni_flags |= IEEE80211_NODE_PWR_MGT; 490 IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 491 "power save mode on, %u sta's in ps mode", vap->iv_ps_sta); 492 493 if (update) 494 vap->iv_update_ps(vap, vap->iv_ps_sta); 495 } else { 496 if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) { 497 vap->iv_ps_sta--; 498 update = 1; 499 } 500 ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT; 501 IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 502 "power save mode off, %u sta's in ps mode", vap->iv_ps_sta); 503 504 /* NB: order here is intentional so TIM is clear before flush */ 505 if (vap->iv_set_tim != NULL) 506 vap->iv_set_tim(ni, 0); 507 if (update) { 508 /* NB if no sta's in ps, driver should flush mc q */ 509 vap->iv_update_ps(vap, vap->iv_ps_sta); 510 } 511 if (ni->ni_psq.psq_len != 0) 512 pwrsave_flushq(ni); 513 } 514 } 515 516 /* 517 * Handle power-save state change in station mode. 518 */ 519 void 520 ieee80211_sta_pwrsave(struct ieee80211vap *vap, int enable) 521 { 522 struct ieee80211_node *ni = vap->iv_bss; 523 524 if (!((enable != 0) ^ ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) != 0))) 525 return; 526 527 IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 528 "sta power save mode %s", enable ? "on" : "off"); 529 if (!enable) { 530 ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT; 531 ieee80211_send_nulldata(ieee80211_ref_node(ni)); 532 /* 533 * Flush any queued frames; we can do this immediately 534 * because we know they'll be queued behind the null 535 * data frame we send the ap. 536 * XXX can we use a data frame to take us out of ps? 537 */ 538 if (ni->ni_psq.psq_len != 0) 539 pwrsave_flushq(ni); 540 } else { 541 ni->ni_flags |= IEEE80211_NODE_PWR_MGT; 542 ieee80211_send_nulldata(ieee80211_ref_node(ni)); 543 } 544 } 545 546 /* 547 * Handle being notified that we have data available for us in a TIM/ATIM. 548 * 549 * This may schedule a transition from _SLEEP -> _RUN if it's appropriate. 550 * 551 * In STA mode, we may have put to sleep during scan and need to be dragged 552 * back out of powersave mode. 553 */ 554 void 555 ieee80211_sta_tim_notify(struct ieee80211vap *vap, int set) 556 { 557 struct ieee80211com *ic = vap->iv_ic; 558 559 /* 560 * Schedule the driver state change. It'll happen at some point soon. 561 * Since the hardware shouldn't know that we're running just yet 562 * (and thus tell the peer that we're awake before we actually wake 563 * up said hardware), we leave the actual node state transition 564 * up to the transition to RUN. 565 * 566 * XXX TODO: verify that the transition to RUN will wake up the 567 * BSS node! 568 */ 569 IEEE80211_LOCK(vap->iv_ic); 570 if (set == 1 && vap->iv_state == IEEE80211_S_SLEEP) { 571 ieee80211_new_state_locked(vap, IEEE80211_S_RUN, 0); 572 IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, 573 "%s: TIM=%d; wakeup\n", __func__, set); 574 } else if ((set == 1) && (ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN)) { 575 /* 576 * XXX only do this if we're in RUN state? 577 */ 578 IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, 579 "%s: wake up from bgscan vap sleep\n", 580 __func__); 581 /* 582 * We may be in BGSCAN mode - this means the VAP is is in STA 583 * mode powersave. If it is, we need to wake it up so we 584 * can process outbound traffic. 585 */ 586 vap->iv_sta_ps(vap, 0); 587 } 588 IEEE80211_UNLOCK(vap->iv_ic); 589 } 590 591 /* 592 * Timer check on whether the VAP has had any transmit activity. 593 * 594 * This may schedule a transition from _RUN -> _SLEEP if it's appropriate. 595 */ 596 void 597 ieee80211_sta_ps_timer_check(struct ieee80211vap *vap) 598 { 599 struct ieee80211com *ic = vap->iv_ic; 600 601 /* XXX lock assert */ 602 603 /* For no, only do this in STA mode */ 604 if (! (vap->iv_caps & IEEE80211_C_SWSLEEP)) 605 goto out; 606 607 if (vap->iv_opmode != IEEE80211_M_STA) 608 goto out; 609 610 /* If we're not at run state, bail */ 611 if (vap->iv_state != IEEE80211_S_RUN) 612 goto out; 613 614 IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, 615 "%s: lastdata=%llu, ticks=%llu\n", 616 __func__, (unsigned long long) ic->ic_lastdata, 617 (unsigned long long) ticks); 618 619 /* If powersave is disabled on the VAP, don't bother */ 620 if (! (vap->iv_flags & IEEE80211_F_PMGTON)) 621 goto out; 622 623 /* If we've done any data within our idle interval, bail */ 624 /* XXX hard-coded to one second for now, ew! */ 625 if (time_after(ic->ic_lastdata + 500, ticks)) 626 goto out; 627 628 /* 629 * Signify we're going into power save and transition the 630 * node to powersave. 631 */ 632 if ((vap->iv_bss->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) 633 vap->iv_sta_ps(vap, 1); 634 635 /* 636 * XXX The driver has to handle the fact that we're going 637 * to sleep but frames may still be transmitted; 638 * hopefully it and/or us will do the right thing and mark any 639 * transmitted frames with PWRMGT set to 1. 640 */ 641 ieee80211_new_state_locked(vap, IEEE80211_S_SLEEP, 0); 642 643 IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, 644 "%s: time delta=%d msec\n", __func__, 645 (int) ticks_to_msecs(ticks - ic->ic_lastdata)); 646 647 out: 648 return; 649 } 650