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_media.h> 42 #include <net/ethernet.h> 43 44 #include <net80211/ieee80211_var.h> 45 46 #include <net/bpf.h> 47 48 static void ieee80211_update_ps(struct ieee80211vap *, int); 49 static int ieee80211_set_tim(struct ieee80211_node *, int); 50 51 MALLOC_DEFINE(M_80211_POWER, "80211power", "802.11 power save state"); 52 53 void 54 ieee80211_power_attach(struct ieee80211com *ic) 55 { 56 } 57 58 void 59 ieee80211_power_detach(struct ieee80211com *ic) 60 { 61 } 62 63 void 64 ieee80211_power_vattach(struct ieee80211vap *vap) 65 { 66 if (vap->iv_opmode == IEEE80211_M_HOSTAP || 67 vap->iv_opmode == IEEE80211_M_IBSS) { 68 /* NB: driver should override */ 69 vap->iv_update_ps = ieee80211_update_ps; 70 vap->iv_set_tim = ieee80211_set_tim; 71 } 72 } 73 74 void 75 ieee80211_power_latevattach(struct ieee80211vap *vap) 76 { 77 /* 78 * Allocate these only if needed. Beware that we 79 * know adhoc mode doesn't support ATIM yet... 80 */ 81 if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 82 vap->iv_tim_len = howmany(vap->iv_max_aid,8) * sizeof(uint8_t); 83 MALLOC(vap->iv_tim_bitmap, uint8_t *, vap->iv_tim_len, 84 M_80211_POWER, M_NOWAIT | M_ZERO); 85 if (vap->iv_tim_bitmap == NULL) { 86 printf("%s: no memory for TIM bitmap!\n", __func__); 87 /* XXX good enough to keep from crashing? */ 88 vap->iv_tim_len = 0; 89 } 90 } 91 } 92 93 void 94 ieee80211_power_vdetach(struct ieee80211vap *vap) 95 { 96 if (vap->iv_tim_bitmap != NULL) { 97 FREE(vap->iv_tim_bitmap, M_80211_POWER); 98 vap->iv_tim_bitmap = NULL; 99 } 100 } 101 102 /* 103 * Clear any frames queued on a node's power save queue. 104 * The number of frames that were present is returned. 105 */ 106 int 107 ieee80211_node_saveq_drain(struct ieee80211_node *ni) 108 { 109 int qlen; 110 111 IEEE80211_NODE_SAVEQ_LOCK(ni); 112 qlen = IEEE80211_NODE_SAVEQ_QLEN(ni); 113 _IF_DRAIN(&ni->ni_savedq); 114 IEEE80211_NODE_SAVEQ_UNLOCK(ni); 115 116 return qlen; 117 } 118 119 /* 120 * Age frames on the power save queue. The aging interval is 121 * 4 times the listen interval specified by the station. This 122 * number is factored into the age calculations when the frame 123 * is placed on the queue. We store ages as time differences 124 * so we can check and/or adjust only the head of the list. 125 * If a frame's age exceeds the threshold then discard it. 126 * The number of frames discarded is returned so the caller 127 * can check if it needs to adjust the tim. 128 */ 129 int 130 ieee80211_node_saveq_age(struct ieee80211_node *ni) 131 { 132 int discard = 0; 133 134 if (IEEE80211_NODE_SAVEQ_QLEN(ni) != 0) { 135 #ifdef IEEE80211_DEBUG 136 struct ieee80211vap *vap = ni->ni_vap; 137 #endif 138 struct mbuf *m; 139 140 IEEE80211_NODE_SAVEQ_LOCK(ni); 141 while (IF_POLL(&ni->ni_savedq, m) != NULL && 142 M_AGE_GET(m) < IEEE80211_INACT_WAIT) { 143 IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 144 "discard frame, age %u", M_AGE_GET(m)); 145 _IEEE80211_NODE_SAVEQ_DEQUEUE_HEAD(ni, m); 146 m_freem(m); 147 discard++; 148 } 149 if (m != NULL) 150 M_AGE_SUB(m, IEEE80211_INACT_WAIT); 151 IEEE80211_NODE_SAVEQ_UNLOCK(ni); 152 153 IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 154 "discard %u frames for age", discard); 155 IEEE80211_NODE_STAT_ADD(ni, ps_discard, discard); 156 } 157 return discard; 158 } 159 160 /* 161 * Handle a change in the PS station occupancy. 162 */ 163 static void 164 ieee80211_update_ps(struct ieee80211vap *vap, int nsta) 165 { 166 167 KASSERT(vap->iv_opmode == IEEE80211_M_HOSTAP || 168 vap->iv_opmode == IEEE80211_M_IBSS, 169 ("operating mode %u", vap->iv_opmode)); 170 } 171 172 /* 173 * Indicate whether there are frames queued for a station in power-save mode. 174 */ 175 static int 176 ieee80211_set_tim(struct ieee80211_node *ni, int set) 177 { 178 struct ieee80211vap *vap = ni->ni_vap; 179 struct ieee80211com *ic = ni->ni_ic; 180 uint16_t aid; 181 int changed; 182 183 KASSERT(vap->iv_opmode == IEEE80211_M_HOSTAP || 184 vap->iv_opmode == IEEE80211_M_IBSS, 185 ("operating mode %u", vap->iv_opmode)); 186 187 aid = IEEE80211_AID(ni->ni_associd); 188 KASSERT(aid < vap->iv_max_aid, 189 ("bogus aid %u, max %u", aid, vap->iv_max_aid)); 190 191 IEEE80211_LOCK(ic); 192 changed = (set != (isset(vap->iv_tim_bitmap, aid) != 0)); 193 if (changed) { 194 if (set) { 195 setbit(vap->iv_tim_bitmap, aid); 196 vap->iv_ps_pending++; 197 } else { 198 clrbit(vap->iv_tim_bitmap, aid); 199 vap->iv_ps_pending--; 200 } 201 /* NB: we know vap is in RUN state so no need to check */ 202 vap->iv_update_beacon(vap, IEEE80211_BEACON_TIM); 203 } 204 IEEE80211_UNLOCK(ic); 205 206 return changed; 207 } 208 209 /* 210 * Save an outbound packet for a node in power-save sleep state. 211 * The new packet is placed on the node's saved queue, and the TIM 212 * is changed, if necessary. 213 */ 214 void 215 ieee80211_pwrsave(struct ieee80211_node *ni, struct mbuf *m) 216 { 217 struct ieee80211vap *vap = ni->ni_vap; 218 struct ieee80211com *ic = ni->ni_ic; 219 int qlen, age; 220 221 IEEE80211_NODE_SAVEQ_LOCK(ni); 222 if (_IF_QFULL(&ni->ni_savedq)) { 223 _IF_DROP(&ni->ni_savedq); 224 IEEE80211_NODE_SAVEQ_UNLOCK(ni); 225 IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni, 226 "pwr save q overflow, drops %d (size %d)", 227 ni->ni_savedq.ifq_drops, IEEE80211_PS_MAX_QUEUE); 228 #ifdef IEEE80211_DEBUG 229 if (ieee80211_msg_dumppkts(vap)) 230 ieee80211_dump_pkt(ni->ni_ic, mtod(m, caddr_t), 231 m->m_len, -1, -1); 232 #endif 233 m_freem(m); 234 return; 235 } 236 /* 237 * Tag the frame with it's expiry time and insert 238 * it in the queue. The aging interval is 4 times 239 * the listen interval specified by the station. 240 * Frames that sit around too long are reclaimed 241 * using this information. 242 */ 243 /* TU -> secs. XXX handle overflow? */ 244 age = IEEE80211_TU_TO_MS((ni->ni_intval * ic->ic_bintval) << 2) / 1000; 245 _IEEE80211_NODE_SAVEQ_ENQUEUE(ni, m, qlen, age); 246 IEEE80211_NODE_SAVEQ_UNLOCK(ni); 247 248 IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 249 "save frame with age %d, %u now queued", age, qlen); 250 251 if (qlen == 1 && vap->iv_set_tim != NULL) 252 vap->iv_set_tim(ni, 1); 253 } 254 255 /* 256 * Unload the frames from the ps q but don't send them 257 * to the driver yet. We do this in two stages to minimize 258 * locking but also because there's no easy way to preserve 259 * ordering given the existing ifnet access mechanisms. 260 * XXX could be optimized 261 */ 262 static void 263 pwrsave_flushq(struct ieee80211_node *ni) 264 { 265 struct mbuf *m, *mhead, *mtail; 266 int mcount; 267 268 IEEE80211_NODE_SAVEQ_LOCK(ni); 269 mcount = IEEE80211_NODE_SAVEQ_QLEN(ni); 270 mhead = mtail = NULL; 271 for (;;) { 272 _IEEE80211_NODE_SAVEQ_DEQUEUE_HEAD(ni, m); 273 if (m == NULL) 274 break; 275 if (mhead == NULL) { 276 mhead = m; 277 m->m_nextpkt = NULL; 278 } else 279 mtail->m_nextpkt = m; 280 mtail = m; 281 } 282 IEEE80211_NODE_SAVEQ_UNLOCK(ni); 283 if (mhead != NULL) { 284 /* XXX need different driver interface */ 285 /* XXX bypasses q max and OACTIVE */ 286 struct ifnet *ifp = ni->ni_vap->iv_ifp; 287 IF_PREPEND_LIST(&ifp->if_snd, mhead, mtail, mcount); 288 if_start(ifp); 289 } 290 } 291 292 /* 293 * Handle station power-save state change. 294 */ 295 void 296 ieee80211_node_pwrsave(struct ieee80211_node *ni, int enable) 297 { 298 struct ieee80211vap *vap = ni->ni_vap; 299 int update; 300 301 update = 0; 302 if (enable) { 303 if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) == 0) { 304 vap->iv_ps_sta++; 305 update = 1; 306 } 307 ni->ni_flags |= IEEE80211_NODE_PWR_MGT; 308 IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 309 "power save mode on, %u sta's in ps mode", vap->iv_ps_sta); 310 311 if (update) 312 vap->iv_update_ps(vap, vap->iv_ps_sta); 313 } else { 314 if (ni->ni_flags & IEEE80211_NODE_PWR_MGT) { 315 vap->iv_ps_sta--; 316 update = 1; 317 } 318 ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT; 319 IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 320 "power save mode off, %u sta's in ps mode", vap->iv_ps_sta); 321 322 /* NB: order here is intentional so TIM is clear before flush */ 323 if (vap->iv_set_tim != NULL) 324 vap->iv_set_tim(ni, 0); 325 if (update) { 326 /* NB if no sta's in ps, driver should flush mc q */ 327 vap->iv_update_ps(vap, vap->iv_ps_sta); 328 } 329 pwrsave_flushq(ni); 330 } 331 } 332 333 /* 334 * Handle power-save state change in station mode. 335 */ 336 void 337 ieee80211_sta_pwrsave(struct ieee80211vap *vap, int enable) 338 { 339 struct ieee80211_node *ni = vap->iv_bss; 340 int qlen; 341 342 if (!((enable != 0) ^ ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) != 0))) 343 return; 344 345 IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 346 "sta power save mode %s", enable ? "on" : "off"); 347 if (!enable) { 348 ni->ni_flags &= ~IEEE80211_NODE_PWR_MGT; 349 ieee80211_send_nulldata(ieee80211_ref_node(ni)); 350 /* 351 * Flush any queued frames; we can do this immediately 352 * because we know they'll be queued behind the null 353 * data frame we send the ap. 354 * XXX can we use a data frame to take us out of ps? 355 */ 356 qlen = IEEE80211_NODE_SAVEQ_QLEN(ni); 357 if (qlen != 0) { 358 IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni, 359 "flush ps queue, %u packets queued", qlen); 360 pwrsave_flushq(ni); 361 } 362 } else { 363 ni->ni_flags |= IEEE80211_NODE_PWR_MGT; 364 ieee80211_send_nulldata(ieee80211_ref_node(ni)); 365 } 366 } 367