update madwifi
[linux-2.6/zen-sources.git] / drivers / net / wireless / madwifi / net80211 / ieee80211_beacon.c
blob7484adafb501cedb694eb98599a76de53c6e5afb
1 /*-
2 * Copyright (c) 2001 Atsushi Onoe
3 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * Alternatively, this software may be distributed under the terms of the
18 * GNU General Public License ("GPL") version 2 as published by the Free
19 * Software Foundation.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * $Id: ieee80211_beacon.c 3783 2008-07-17 03:44:41Z proski $
34 #ifndef EXPORT_SYMTAB
35 #define EXPORT_SYMTAB
36 #endif
39 * IEEE 802.11 beacon handling routines
41 #ifndef AUTOCONF_INCLUDED
42 #include <linux/config.h>
43 #endif
44 #include <linux/version.h>
45 #include <linux/module.h>
46 #include <linux/skbuff.h>
47 #include <linux/netdevice.h>
48 #include <linux/if_vlan.h>
50 #include "if_media.h"
51 #include <net80211/ieee80211_var.h>
54 static u_int8_t *
55 ieee80211_beacon_init(struct ieee80211_node *ni, struct ieee80211_beacon_offsets *bo,
56 u_int8_t *frm)
58 struct ieee80211vap *vap = ni->ni_vap;
59 struct ieee80211com *ic = ni->ni_ic;
60 u_int16_t capinfo;
61 struct ieee80211_rateset *rs = &ni->ni_rates;
63 KASSERT(ic->ic_bsschan != IEEE80211_CHAN_ANYC, ("no bss chan"));
65 /* XXX timestamp is set by hardware/driver */
66 memset(frm, 0, 8);
67 frm += 8;
69 /* beacon interval */
70 *(__le16 *)frm = htole16(ni->ni_intval);
71 frm += 2;
73 /* capability information */
74 if (vap->iv_opmode == IEEE80211_M_IBSS)
75 capinfo = IEEE80211_CAPINFO_IBSS;
76 else
77 capinfo = IEEE80211_CAPINFO_ESS;
78 if (vap->iv_flags & IEEE80211_F_PRIVACY)
79 capinfo |= IEEE80211_CAPINFO_PRIVACY;
80 if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
81 IEEE80211_IS_CHAN_2GHZ(ic->ic_bsschan))
82 capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
83 if (ic->ic_flags & IEEE80211_F_SHSLOT)
84 capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
85 if (ic->ic_flags & IEEE80211_F_DOTH)
86 capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT;
87 bo->bo_caps = (__le16 *)frm;
88 *(__le16 *)frm = htole16(capinfo);
89 frm += 2;
91 /* ssid */
92 *frm++ = IEEE80211_ELEMID_SSID;
93 if ((vap->iv_flags & IEEE80211_F_HIDESSID) == 0) {
94 *frm++ = ni->ni_esslen;
95 memcpy(frm, ni->ni_essid, ni->ni_esslen);
96 frm += ni->ni_esslen;
97 } else
98 *frm++ = 0;
100 /* supported rates */
101 frm = ieee80211_add_rates(frm, rs);
104 /* XXX: better way to check this? */
105 /* XXX: how about DS ? */
106 if (!IEEE80211_IS_CHAN_FHSS(ic->ic_bsschan)) {
107 *frm++ = IEEE80211_ELEMID_DSPARMS;
108 *frm++ = 1;
109 *frm++ = ieee80211_chan2ieee(ic, ic->ic_bsschan);
111 bo->bo_tim = frm;
113 /* IBSS/TIM */
114 if (vap->iv_opmode == IEEE80211_M_IBSS) {
115 *frm++ = IEEE80211_ELEMID_IBSSPARMS;
116 *frm++ = 2;
117 *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */
118 bo->bo_tim_len = 0;
119 } else {
120 struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *)frm;
122 tie->tim_ie = IEEE80211_ELEMID_TIM;
123 tie->tim_len = 4; /* length */
124 tie->tim_count = 0; /* DTIM count */
125 tie->tim_period = vap->iv_dtim_period; /* DTIM period */
126 tie->tim_bitctl = 0; /* bitmap control */
127 tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */
128 frm += sizeof(struct ieee80211_tim_ie);
129 bo->bo_tim_len = 1;
131 bo->bo_tim_trailer = frm;
133 /* country */
134 if ((ic->ic_flags & IEEE80211_F_DOTH) ||
135 (ic->ic_flags_ext & IEEE80211_FEXT_COUNTRYIE))
136 frm = ieee80211_add_country(frm, ic);
138 /* power constraint */
139 if (ic->ic_flags & IEEE80211_F_DOTH)
140 frm = ieee80211_add_pwrcnstr(frm, ic);
142 /* channel switch announcement */
143 bo->bo_chanswitch = frm;
145 /* ERP */
146 if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan)) {
147 bo->bo_erp = frm;
148 frm = ieee80211_add_erp(frm, ic);
151 /* Ext. Supp. Rates */
152 frm = ieee80211_add_xrates(frm, rs);
154 /* WME */
155 if (vap->iv_flags & IEEE80211_F_WME) {
156 bo->bo_wme = frm;
157 frm = ieee80211_add_wme_param(frm, &ic->ic_wme, IEEE80211_VAP_UAPSD_ENABLED(vap));
158 vap->iv_flags &= ~IEEE80211_F_WMEUPDATE;
161 /* WPA 1+2 */
162 if (vap->iv_flags & IEEE80211_F_WPA)
163 frm = ieee80211_add_wpa(frm, vap);
165 /* athAdvCaps */
166 bo->bo_ath_caps = frm;
167 if (vap->iv_bss && vap->iv_bss->ni_ath_flags)
168 frm = ieee80211_add_athAdvCap(frm, vap->iv_bss->ni_ath_flags,
169 vap->iv_bss->ni_ath_defkeyindex);
171 /* XR */
172 bo->bo_xr = frm;
173 #ifdef ATH_SUPERG_XR
174 if (vap->iv_xrvap && vap->iv_ath_cap & IEEE80211_ATHC_XR) /* XR */
175 frm = ieee80211_add_xr_param(frm, vap);
176 #endif
177 bo->bo_appie_buf = frm;
178 bo->bo_appie_buf_len = 0;
180 bo->bo_tim_trailerlen = frm - bo->bo_tim_trailer;
181 bo->bo_chanswitch_trailerlen = frm - bo->bo_chanswitch;
183 return frm;
188 * Allocate a beacon frame and fillin the appropriate bits.
190 struct sk_buff *
191 ieee80211_beacon_alloc(struct ieee80211_node *ni,
192 struct ieee80211_beacon_offsets *bo)
194 struct ieee80211vap *vap = ni->ni_vap;
195 struct ieee80211com *ic = ni->ni_ic;
196 struct ieee80211_frame *wh;
197 struct sk_buff *skb;
198 int pktlen;
199 u_int8_t *frm;
200 struct ieee80211_rateset *rs;
203 * beacon frame format
204 * [8] time stamp
205 * [2] beacon interval
206 * [2] capability information
207 * [tlv] ssid
208 * [tlv] supported rates
209 * [7] FH/DS parameter set
210 * [tlv] IBSS/TIM parameter set
211 * [tlv] country code
212 * [3] power constraint
213 * [5] channel switch announcement
214 * [3] extended rate phy (ERP)
215 * [tlv] extended supported rates
216 * [tlv] WME parameters
217 * [tlv] WPA/RSN parameters
218 * [tlv] Atheros Advanced Capabilities
219 * [tlv] AtherosXR parameters
220 * XXX Vendor-specific OIDs (e.g. Atheros)
221 * NB: we allocate the max space required for the TIM bitmap.
223 rs = &ni->ni_rates;
224 pktlen = 8 /* time stamp */
225 + sizeof(u_int16_t) /* beacon interval */
226 + sizeof(u_int16_t) /* capability information */
227 + 2 + ni->ni_esslen /* ssid */
228 + 2 + IEEE80211_RATE_SIZE /* supported rates */
229 + 7 /* FH/DS parameters max(7,3) */
230 + 2 + 4 + vap->iv_tim_len /* IBSS/TIM parameter set*/
231 + ic->ic_country_ie.country_len + 2 /* country code */
232 + 3 /* power constraint */
233 + 5 /* channel switch announcement */
234 + 3 /* ERP */
235 + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) /* Ext. Supp. Rates */
236 + (vap->iv_caps & IEEE80211_C_WME ? /* WME */
237 sizeof(struct ieee80211_wme_param) : 0)
238 + (vap->iv_caps & IEEE80211_C_WPA ? /* WPA 1+2 */
239 2 * sizeof(struct ieee80211_ie_wpa) : 0)
240 + sizeof(struct ieee80211_ie_athAdvCap)
241 #ifdef ATH_SUPERG_XR
242 + (ic->ic_ath_cap & IEEE80211_ATHC_XR ? /* XR */
243 sizeof(struct ieee80211_xr_param) : 0)
244 #endif
246 skb = ieee80211_getmgtframe(&frm, pktlen);
247 if (skb == NULL) {
248 IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni,
249 "%s: cannot get buf; size %u", __func__, pktlen);
250 vap->iv_stats.is_tx_nobuf++;
251 return NULL;
254 SKB_NI(skb) = ieee80211_ref_node(ni);
256 frm = ieee80211_beacon_init(ni, bo, frm);
258 skb_trim(skb, frm - skb->data);
260 wh = (struct ieee80211_frame *)
261 skb_push(skb, sizeof(struct ieee80211_frame));
262 wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
263 IEEE80211_FC0_SUBTYPE_BEACON;
264 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
265 wh->i_dur = 0;
266 IEEE80211_ADDR_COPY(wh->i_addr1, ic->ic_dev->broadcast);
267 IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
268 IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bssid);
269 IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
270 "%s: beacon bssid:" MAC_FMT "\n",
271 __func__, MAC_ADDR(wh->i_addr3));
272 *(u_int16_t *)wh->i_seq = 0;
274 return skb;
276 EXPORT_SYMBOL(ieee80211_beacon_alloc);
279 * Update the dynamic parts of a beacon frame based on the current state.
282 ieee80211_beacon_update(struct ieee80211_node *ni,
283 struct ieee80211_beacon_offsets *bo, struct sk_buff *skb,
284 int mcast, int *is_dtim)
286 struct ieee80211vap *vap = ni->ni_vap;
287 struct ieee80211com *ic = ni->ni_ic;
288 int len_changed = 0;
289 u_int16_t capinfo;
291 IEEE80211_LOCK_IRQ(ic);
293 /* Check if we need to change channel right now */
294 if ((ic->ic_flags & IEEE80211_F_DOTH) &&
295 (vap->iv_flags & IEEE80211_F_CHANSWITCH)) {
296 struct ieee80211_channel *c =
297 ieee80211_doth_findchan(vap, ic->ic_chanchange_chan);
299 if (!vap->iv_chanchange_count && !c) {
300 vap->iv_flags &= ~IEEE80211_F_CHANSWITCH;
301 ic->ic_flags &= ~IEEE80211_F_CHANSWITCH;
302 } else if (vap->iv_chanchange_count &&
303 ((!ic->ic_chanchange_tbtt) ||
304 (vap->iv_chanchange_count == ic->ic_chanchange_tbtt))) {
305 u_int8_t *frm;
307 IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
308 "%s: reinit beacon\n", __func__);
310 /* NB: ic_bsschan is in the DSPARMS beacon IE, so must
311 * set this prior to the beacon re-init, below. */
312 if (c == NULL) {
313 /* Requested channel invalid; drop the channel
314 * switch announcement and do nothing. */
315 IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
316 "%s: find channel failure\n", __func__);
317 } else
318 ic->ic_bsschan = c;
320 skb_pull(skb, sizeof(struct ieee80211_frame));
321 skb_trim(skb, 0);
322 frm = skb->data;
323 skb_put(skb, ieee80211_beacon_init(ni, bo, frm) - frm);
324 skb_push(skb, sizeof(struct ieee80211_frame));
326 vap->iv_chanchange_count = 0;
327 vap->iv_flags &= ~IEEE80211_F_CHANSWITCH;
328 ic->ic_flags &= ~IEEE80211_F_CHANSWITCH;
330 /* NB: Only for the first VAP to get here, and when we
331 * have a valid channel to which to change. */
332 if (c && (ic->ic_curchan != c)) {
333 ic->ic_curchan = c;
334 ic->ic_set_channel(ic);
337 len_changed = 1;
341 /* XXX faster to recalculate entirely or just changes? */
342 if (vap->iv_opmode == IEEE80211_M_IBSS)
343 capinfo = IEEE80211_CAPINFO_IBSS;
344 else
345 capinfo = IEEE80211_CAPINFO_ESS;
347 if (vap->iv_flags & IEEE80211_F_PRIVACY)
348 capinfo |= IEEE80211_CAPINFO_PRIVACY;
349 if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
350 IEEE80211_IS_CHAN_2GHZ(ic->ic_bsschan))
351 capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
352 if (ic->ic_flags & IEEE80211_F_SHSLOT)
353 capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
354 if (ic->ic_flags & IEEE80211_F_DOTH)
355 capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT;
357 *bo->bo_caps = htole16(capinfo);
359 if (vap->iv_flags & IEEE80211_F_WME) {
360 struct ieee80211_wme_state *wme = &ic->ic_wme;
363 * Check for aggressive mode change. When there is
364 * significant high priority traffic in the BSS
365 * throttle back BE traffic by using conservative
366 * parameters. Otherwise BE uses aggressive params
367 * to optimize performance of legacy/non-QoS traffic.
369 if (wme->wme_flags & WME_F_AGGRMODE) {
370 if (wme->wme_hipri_traffic >
371 wme->wme_hipri_switch_thresh) {
372 IEEE80211_NOTE(vap, IEEE80211_MSG_WME, ni,
373 "%s: traffic %u, disable aggressive mode",
374 __func__, wme->wme_hipri_traffic);
375 wme->wme_flags &= ~WME_F_AGGRMODE;
376 ieee80211_wme_updateparams_locked(vap);
377 wme->wme_hipri_traffic =
378 wme->wme_hipri_switch_hysteresis;
379 } else
380 wme->wme_hipri_traffic = 0;
381 } else {
382 if (wme->wme_hipri_traffic <=
383 wme->wme_hipri_switch_thresh) {
384 IEEE80211_NOTE(vap, IEEE80211_MSG_WME, ni,
385 "%s: traffic %u, enable aggressive mode",
386 __func__, wme->wme_hipri_traffic);
387 wme->wme_flags |= WME_F_AGGRMODE;
388 ieee80211_wme_updateparams_locked(vap);
389 wme->wme_hipri_traffic = 0;
390 } else
391 wme->wme_hipri_traffic =
392 wme->wme_hipri_switch_hysteresis;
394 /* XXX multi-bss */
395 if (vap->iv_flags & IEEE80211_F_WMEUPDATE) {
396 (void) ieee80211_add_wme_param(bo->bo_wme, wme, IEEE80211_VAP_UAPSD_ENABLED(vap));
397 vap->iv_flags &= ~IEEE80211_F_WMEUPDATE;
401 if (vap->iv_opmode == IEEE80211_M_HOSTAP) { /* NB: no IBSS support*/
402 struct ieee80211_tim_ie *tie =
403 (struct ieee80211_tim_ie *)bo->bo_tim;
404 if (vap->iv_flags & IEEE80211_F_TIMUPDATE) {
405 u_int timlen, timoff, i;
407 * ATIM/DTIM needs updating. If it fits in the
408 * current space allocated then just copy in the
409 * new bits. Otherwise we need to move any trailing
410 * data to make room. Note that we know there is
411 * contiguous space because ieee80211_beacon_allocate
412 * ensures there is space in the mbuf to write a
413 * maximal-size virtual bitmap (based on ic_max_aid).
416 * Calculate the bitmap size and offset, copy any
417 * trailer out of the way, and then copy in the
418 * new bitmap and update the information element.
419 * Note that the tim bitmap must contain at least
420 * one byte and any offset must be even.
422 if (vap->iv_ps_pending != 0) {
423 timoff = 128; /* impossibly large */
424 for (i = 0; i < vap->iv_tim_len; i++)
425 if (vap->iv_tim_bitmap[i]) {
426 timoff = i & BITCTL_BUFD_UCAST_AID_MASK;
427 break;
429 KASSERT(timoff != 128, ("tim bitmap empty!"));
430 for (i = vap->iv_tim_len-1; i >= timoff; i--)
431 if (vap->iv_tim_bitmap[i])
432 break;
433 timlen = 1 + (i - timoff);
434 } else {
435 timoff = 0;
436 timlen = 1;
438 if (timlen != bo->bo_tim_len) {
439 /* copy up/down trailer */
440 int trailer_adjust =
441 (tie->tim_bitmap+timlen) - (bo->bo_tim_trailer);
442 memmove(tie->tim_bitmap+timlen, bo->bo_tim_trailer,
443 bo->bo_tim_trailerlen);
444 bo->bo_tim_trailer = tie->tim_bitmap+timlen;
445 bo->bo_chanswitch += trailer_adjust;
446 bo->bo_wme += trailer_adjust;
447 bo->bo_erp += trailer_adjust;
448 bo->bo_ath_caps += trailer_adjust;
449 bo->bo_xr += trailer_adjust;
450 if (timlen > bo->bo_tim_len)
451 skb_put(skb, timlen - bo->bo_tim_len);
452 else
453 skb_trim(skb, skb->len - (bo->bo_tim_len - timlen));
454 bo->bo_tim_len = timlen;
456 /* update information element */
457 tie->tim_len = 3 + timlen;
458 tie->tim_bitctl = timoff;
459 len_changed = 1;
461 memcpy(tie->tim_bitmap, vap->iv_tim_bitmap + timoff,
462 bo->bo_tim_len);
464 vap->iv_flags &= ~IEEE80211_F_TIMUPDATE;
466 IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
467 "%s: TIM updated, pending %u, off %u, len %u",
468 __func__, vap->iv_ps_pending, timoff, timlen);
470 /* count down DTIM period */
471 if (tie->tim_count == 0)
472 tie->tim_count = tie->tim_period - 1;
473 else
474 tie->tim_count--;
475 /* update state for buffered multicast frames on DTIM */
476 if (mcast && (tie->tim_count == 0))
477 tie->tim_bitctl |= BITCTL_BUFD_MCAST;
478 else
479 tie->tim_bitctl &= ~BITCTL_BUFD_MCAST;
480 *is_dtim = (tie->tim_count == 0);
483 /* Whenever we want to switch to a new channel, we need to follow the
484 * following steps:
486 * - iv_chanchange_count= number of beacon intervals elapsed (0)
487 * - ic_chanchange_tbtt = number of beacon intervals before switching
488 * - ic_chanchange_chan = IEEE channel number after switching
489 * - ic_flags |= IEEE80211_F_CHANSWITCH */
491 if (IEEE80211_IS_MODE_BEACON(vap->iv_opmode)) {
493 if ((ic->ic_flags & IEEE80211_F_DOTH) &&
494 (ic->ic_flags & IEEE80211_F_CHANSWITCH)) {
495 struct ieee80211_ie_csa *csa_ie =
496 (struct ieee80211_ie_csa *)bo->bo_chanswitch;
498 IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
499 "%s: Sending 802.11h chanswitch IE: "
500 "%d/%d\n", __func__,
501 ic->ic_chanchange_chan,
502 ic->ic_chanchange_tbtt);
503 if (!vap->iv_chanchange_count) {
504 vap->iv_flags |= IEEE80211_F_CHANSWITCH;
506 /* copy out trailer to open up a slot */
507 memmove(bo->bo_chanswitch + sizeof(*csa_ie),
508 bo->bo_chanswitch,
509 bo->bo_chanswitch_trailerlen);
511 /* add ie in opened slot */
512 csa_ie->csa_id = IEEE80211_ELEMID_CHANSWITCHANN;
513 /* fixed length */
514 csa_ie->csa_len = sizeof(*csa_ie) - 2;
515 /* STA shall transmit no further frames */
516 csa_ie->csa_mode = 1;
517 csa_ie->csa_chan = ic->ic_chanchange_chan;
518 csa_ie->csa_count = ic->ic_chanchange_tbtt;
520 /* update the trailer lens */
521 bo->bo_chanswitch_trailerlen += sizeof(*csa_ie);
522 bo->bo_tim_trailerlen += sizeof(*csa_ie);
523 bo->bo_wme += sizeof(*csa_ie);
524 bo->bo_erp += sizeof(*csa_ie);
525 bo->bo_ath_caps += sizeof(*csa_ie);
526 bo->bo_xr += sizeof(*csa_ie);
528 /* indicate new beacon length so other layers
529 * may manage memory */
530 skb_put(skb, sizeof(*csa_ie));
531 len_changed = 1;
532 } else if (csa_ie->csa_count)
533 csa_ie->csa_count--;
535 vap->iv_chanchange_count++;
536 IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
537 "%s: CHANSWITCH IE, change in %d TBTT\n",
538 __func__, csa_ie->csa_count);
540 #ifdef ATH_SUPERG_XR
541 if (vap->iv_flags & IEEE80211_F_XRUPDATE) {
542 if (vap->iv_xrvap)
543 (void)ieee80211_add_xr_param(bo->bo_xr, vap);
544 vap->iv_flags &= ~IEEE80211_F_XRUPDATE;
546 #endif
547 if ((ic->ic_flags_ext & IEEE80211_FEXT_ERPUPDATE) &&
548 (bo->bo_erp != NULL)) {
549 (void)ieee80211_add_erp(bo->bo_erp, ic);
550 ic->ic_flags_ext &= ~IEEE80211_FEXT_ERPUPDATE;
553 /* if it is a mode change beacon for dynamic turbo case */
554 if (((ic->ic_ath_cap & IEEE80211_ATHC_BOOST) != 0) ^
555 IEEE80211_IS_CHAN_TURBO(ic->ic_curchan))
556 ieee80211_add_athAdvCap(bo->bo_ath_caps,
557 vap->iv_bss->ni_ath_flags,
558 vap->iv_bss->ni_ath_defkeyindex);
559 /* add APP_IE buffer if app updated it */
560 if (vap->iv_flags_ext & IEEE80211_FEXT_APPIE_UPDATE) {
561 /* adjust the buffer size if the size is changed */
562 if (vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length !=
563 bo->bo_appie_buf_len) {
564 int diff_len;
565 diff_len =
566 vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].
567 length -
568 bo->bo_appie_buf_len;
570 if (diff_len > 0)
571 skb_put(skb, diff_len);
572 else
573 skb_trim(skb, skb->len + diff_len);
575 bo->bo_appie_buf_len =
576 vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].
577 length;
578 /* update the trailer lens */
579 bo->bo_chanswitch_trailerlen += diff_len;
580 bo->bo_tim_trailerlen += diff_len;
582 len_changed = 1;
584 memcpy(bo->bo_appie_buf,
585 vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].ie,
586 vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length);
588 vap->iv_flags_ext &= ~IEEE80211_FEXT_APPIE_UPDATE;
591 IEEE80211_UNLOCK_IRQ(ic);
593 return len_changed;
595 EXPORT_SYMBOL(ieee80211_beacon_update);