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