[svn-upgrade] new version madwifi (0.9.4+r4136.20110203)
[debian/madwifi.git] / net80211 / ieee80211_beacon.c
1 /*-
2  * Copyright (c) 2001 Atsushi Onoe
3  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
4  * All rights reserved.
5  *
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.
16  *
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.
20  *
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.
31  *
32  * $Id: ieee80211_beacon.c 4136 2011-02-02 21:22:31Z proski $
33  */
34 #ifndef EXPORT_SYMTAB
35 #define EXPORT_SYMTAB
36 #endif
37
38 /*
39  * IEEE 802.11 beacon handling routines
40  */
41 #if !defined(AUTOCONF_INCLUDED) && !defined(CONFIG_LOCALVERSION)
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>
49
50 #include "if_media.h"
51 #include <net80211/ieee80211_var.h>
52
53
54 static u_int8_t *
55 ieee80211_beacon_init(struct ieee80211_node *ni, struct ieee80211_beacon_offsets *bo,
56         u_int8_t *frm)
57 {
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;
62
63         KASSERT(ic->ic_bsschan != IEEE80211_CHAN_ANYC, ("no bss chan"));
64
65         /* XXX timestamp is set by hardware/driver */
66         memset(frm, 0, 8);
67         frm += 8;
68
69         /* beacon interval */
70         *(__le16 *)frm = htole16(ni->ni_intval);
71         frm += 2;
72
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;
90
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;
99         
100         /* supported rates */
101         frm = ieee80211_add_rates(frm, rs);
102
103
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);
110         }
111         bo->bo_tim = frm;
112
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;
121
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;
130         }
131         bo->bo_tim_trailer = frm;
132
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);
137         }
138
139         /* power constraint */
140         if (ic->ic_flags & IEEE80211_F_DOTH) {
141                 *frm++ = IEEE80211_ELEMID_PWRCNSTR;
142                 *frm++ = 1;
143                 *frm++ = IEEE80211_PWRCONSTRAINT_VAL(ic);
144         }
145
146         /* XXX: channel switch announcement ? */ 
147         bo->bo_chanswitch = frm;
148
149         /* ERP */
150         if (IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan)) {
151                 bo->bo_erp = frm;
152                 frm = ieee80211_add_erp(frm, ic);
153         }
154
155         /* Ext. Supp. Rates */
156         frm = ieee80211_add_xrates(frm, rs);
157
158         /* WME */
159         if (vap->iv_flags & IEEE80211_F_WME) {
160                 bo->bo_wme = frm;
161                 frm = ieee80211_add_wme_param(frm, &ic->ic_wme, IEEE80211_VAP_UAPSD_ENABLED(vap));
162                 vap->iv_flags &= ~IEEE80211_F_WMEUPDATE;
163         }
164
165         /* WPA 1+2 */
166         if (vap->iv_flags & IEEE80211_F_WPA)
167                 frm = ieee80211_add_wpa(frm, vap);
168
169         /* athAdvCaps */
170         bo->bo_ath_caps = frm;
171         if (vap->iv_bss && vap->iv_bss->ni_ath_flags)
172                 frm = ieee80211_add_athAdvCap(frm, vap->iv_bss->ni_ath_flags,
173                         vap->iv_bss->ni_ath_defkeyindex);
174         
175         /* XR */
176         bo->bo_xr = frm;
177 #ifdef ATH_SUPERG_XR
178         if (vap->iv_xrvap && vap->iv_ath_cap & IEEE80211_ATHC_XR)       /* XR */
179                 frm = ieee80211_add_xr_param(frm, vap);
180 #endif
181         bo->bo_appie_buf = frm;
182         bo->bo_appie_buf_len = 0;
183         
184         bo->bo_tim_trailerlen = frm - bo->bo_tim_trailer;
185         bo->bo_chanswitch_trailerlen = frm - bo->bo_chanswitch;
186
187         return frm;
188 }
189
190
191 /*
192  * Allocate a beacon frame and fillin the appropriate bits.
193  */
194 struct sk_buff *
195 ieee80211_beacon_alloc(struct ieee80211_node *ni,
196         struct ieee80211_beacon_offsets *bo)
197 {
198         struct ieee80211vap *vap = ni->ni_vap;
199         struct ieee80211com *ic = ni->ni_ic;
200         struct ieee80211_frame *wh;
201         struct sk_buff *skb;
202         int pktlen;
203         u_int8_t *frm;
204         struct ieee80211_rateset *rs;
205
206         /*
207          * beacon frame format
208          *      [8] time stamp
209          *      [2] beacon interval
210          *      [2] capability information
211          *      [tlv] ssid
212          *      [tlv] supported rates
213          *      [7] FH/DS parameter set
214          *      [tlv] IBSS/TIM parameter set
215          *      [tlv] country code 
216          *      [3] power constraint
217          *      [5] channel switch announcement
218          *      [3] extended rate phy (ERP)
219          *      [tlv] extended supported rates
220          *      [tlv] WME parameters
221          *      [tlv] WPA/RSN parameters
222          *      [tlv] Atheros Advanced Capabilities
223          *      [tlv] AtherosXR parameters
224          * XXX Vendor-specific OIDs (e.g. Atheros)
225          * NB: we allocate the max space required for the TIM bitmap.
226          */
227         rs = &ni->ni_rates;
228         pktlen =   8                                    /* time stamp */
229                  + sizeof(u_int16_t)                    /* beacon interval */
230                  + sizeof(u_int16_t)                    /* capability information */
231                  + 2 + ni->ni_esslen                    /* ssid */
232                  + 2 + IEEE80211_RATE_SIZE              /* supported rates */
233                  + 7                                    /* FH/DS parameters max(7,3) */
234                  + 2 + 4 + vap->iv_tim_len              /* IBSS/TIM parameter set*/
235                  + ic->ic_country_ie.country_len + 2    /* country code */
236                  + 3                                    /* power constraint */
237                  + 5                                    /* channel switch announcement */
238                  + 3                                    /* ERP */
239                  + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) /* Ext. Supp. Rates */
240                  + (vap->iv_caps & IEEE80211_C_WME ?    /* WME */
241                         sizeof(struct ieee80211_wme_param) : 0)
242                  + (vap->iv_caps & IEEE80211_C_WPA ?    /* WPA 1+2 */
243                         2 * sizeof(struct ieee80211_ie_wpa) : 0)
244                  + sizeof(struct ieee80211_ie_athAdvCap)
245 #ifdef ATH_SUPERG_XR
246                  + (ic->ic_ath_cap & IEEE80211_ATHC_XR ?        /* XR */
247                         sizeof(struct ieee80211_xr_param) : 0)
248 #endif
249                  ;
250         skb = ieee80211_getmgtframe(&frm, pktlen);
251         if (skb == NULL) {
252                 IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni,
253                         "%s: cannot get buf; size %u", __func__, pktlen);
254                 vap->iv_stats.is_tx_nobuf++;
255                 return NULL;
256         }
257
258         frm = ieee80211_beacon_init(ni, bo, frm);
259
260         skb_trim(skb, frm - skb->data);
261
262         wh = (struct ieee80211_frame *)
263                 skb_push(skb, sizeof(struct ieee80211_frame));
264         wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
265                 IEEE80211_FC0_SUBTYPE_BEACON;
266         wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
267         wh->i_dur = 0;
268         IEEE80211_ADDR_COPY(wh->i_addr1, ic->ic_dev->broadcast);
269         IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr);
270         IEEE80211_ADDR_COPY(wh->i_addr3,  vap->iv_bss->ni_bssid);
271         *(u_int16_t *)wh->i_seq = 0;
272
273         return skb;
274 }
275 EXPORT_SYMBOL(ieee80211_beacon_alloc);
276
277 /*
278  * Update the dynamic parts of a beacon frame based on the current state.
279  */
280 int
281 ieee80211_beacon_update(struct ieee80211_node *ni,
282         struct ieee80211_beacon_offsets *bo, struct sk_buff *skb, int mcast)
283 {
284         struct ieee80211vap *vap = ni->ni_vap;
285         struct ieee80211com *ic = ni->ni_ic;
286         struct ieee80211_frame * wh = (struct ieee80211_frame *) skb->data;
287         int len_changed = 0;
288         u_int16_t capinfo;
289
290         IEEE80211_LOCK(ic);
291
292         /* After an IBSS merge, bssid might have been updated */
293         IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bss->ni_bssid);
294
295         /* Check if we need to change channel right now */
296         if ((ic->ic_flags & IEEE80211_F_DOTH) &&
297             (vap->iv_flags & IEEE80211_F_CHANSWITCH) &&
298             (vap->iv_chanchange_count == ic->ic_chanchange_tbtt)) {
299                 u_int8_t *frm;
300                 struct ieee80211_channel *c;
301
302                 vap->iv_chanchange_count = 0;
303
304                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
305                         "%s: reinit beacon\n", __func__);
306
307                 /* 
308                  * NB: ic_bsschan is in the DSPARMS beacon IE, so must set this
309                  *     prior to the beacon re-init, below.
310                  */
311                 c = ieee80211_doth_findchan(vap, ic->ic_chanchange_chan);
312                 if (c == NULL) {
313                         IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
314                                 "%s: find channel failure\n", __func__);
315                         IEEE80211_UNLOCK(ic);
316                         return 0;
317                 }
318                 ic->ic_bsschan = c;
319
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));
325
326                 vap->iv_flags &= ~IEEE80211_F_CHANSWITCH;
327                 ic->ic_flags &= ~IEEE80211_F_CHANSWITCH;
328
329                 /* NB: only for the first VAP to get here */
330                 if (ic->ic_curchan != c) {
331                         ic->ic_curchan = c;
332                         ic->ic_set_channel(ic);
333                 }
334
335                 len_changed = 1;
336         }
337
338         /* XXX faster to recalculate entirely or just changes? */
339         if (vap->iv_opmode == IEEE80211_M_IBSS)
340                 capinfo = IEEE80211_CAPINFO_IBSS;
341         else
342                 capinfo = IEEE80211_CAPINFO_ESS;
343         if (vap->iv_flags & IEEE80211_F_PRIVACY)
344                 capinfo |= IEEE80211_CAPINFO_PRIVACY;
345         if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
346             IEEE80211_IS_CHAN_2GHZ(ic->ic_bsschan))
347                 capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
348         if (ic->ic_flags & IEEE80211_F_SHSLOT)
349                 capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
350         if (ic->ic_flags & IEEE80211_F_DOTH)
351                 capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT;
352
353         *bo->bo_caps = htole16(capinfo);
354
355         if (vap->iv_flags & IEEE80211_F_WME) {
356                 struct ieee80211_wme_state *wme = &ic->ic_wme;
357
358                 /*
359                  * Check for aggressive mode change.  When there is
360                  * significant high priority traffic in the BSS
361                  * throttle back BE traffic by using conservative
362                  * parameters.  Otherwise BE uses aggressive params
363                  * to optimize performance of legacy/non-QoS traffic.
364                  */
365                 if (wme->wme_flags & WME_F_AGGRMODE) {
366                         if (wme->wme_hipri_traffic >
367                             wme->wme_hipri_switch_thresh) {
368                                 IEEE80211_NOTE(vap, IEEE80211_MSG_WME, ni,
369                                         "%s: traffic %u, disable aggressive mode",
370                                         __func__, wme->wme_hipri_traffic);
371                                 wme->wme_flags &= ~WME_F_AGGRMODE;
372                                 ieee80211_wme_updateparams_locked(vap);
373                                 wme->wme_hipri_traffic =
374                                         wme->wme_hipri_switch_hysteresis;
375                         } else
376                                 wme->wme_hipri_traffic = 0;
377                 } else {
378                         if (wme->wme_hipri_traffic <=
379                             wme->wme_hipri_switch_thresh) {
380                                 IEEE80211_NOTE(vap, IEEE80211_MSG_WME, ni,
381                                         "%s: traffic %u, enable aggressive mode",
382                                         __func__, wme->wme_hipri_traffic);
383                                 wme->wme_flags |= WME_F_AGGRMODE;
384                                 ieee80211_wme_updateparams_locked(vap);
385                                 wme->wme_hipri_traffic = 0;
386                         } else
387                                 wme->wme_hipri_traffic =
388                                         wme->wme_hipri_switch_hysteresis;
389                 }
390                 /* XXX multi-bss */
391                 if (vap->iv_flags & IEEE80211_F_WMEUPDATE) {
392                         (void) ieee80211_add_wme_param(bo->bo_wme, wme, IEEE80211_VAP_UAPSD_ENABLED(vap));
393                         vap->iv_flags &= ~IEEE80211_F_WMEUPDATE;
394                 }
395         }
396
397         if (vap->iv_opmode == IEEE80211_M_HOSTAP) {     /* NB: no IBSS support*/
398                 struct ieee80211_tim_ie *tie =
399                         (struct ieee80211_tim_ie *) bo->bo_tim;
400                 if (vap->iv_flags & IEEE80211_F_TIMUPDATE) {
401                         u_int timlen, timoff, i;
402                         /*
403                          * ATIM/DTIM needs updating.  If it fits in the
404                          * current space allocated then just copy in the
405                          * new bits.  Otherwise we need to move any trailing
406                          * data to make room.  Note that we know there is
407                          * contiguous space because ieee80211_beacon_allocate
408                          * ensures there is space in the mbuf to write a
409                          * maximal-size virtual bitmap (based on ic_max_aid).
410                          */
411                         /*
412                          * Calculate the bitmap size and offset, copy any
413                          * trailer out of the way, and then copy in the
414                          * new bitmap and update the information element.
415                          * Note that the tim bitmap must contain at least
416                          * one byte and any offset must be even.
417                          */
418                         if (vap->iv_ps_pending != 0) {
419                                 timoff = 128;           /* impossibly large */
420                                 for (i = 0; i < vap->iv_tim_len; i++)
421                                         if (vap->iv_tim_bitmap[i]) {
422                                                 timoff = i &~ 1;
423                                                 break;
424                                         }
425                                 KASSERT(timoff != 128, ("tim bitmap empty!"));
426                                 for (i = vap->iv_tim_len-1; i >= timoff; i--)
427                                         if (vap->iv_tim_bitmap[i])
428                                                 break;
429                                 timlen = 1 + (i - timoff);
430                         } else {
431                                 timoff = 0;
432                                 timlen = 1;
433                         }
434                         if (timlen != bo->bo_tim_len) {
435                                 /* copy up/down trailer */
436                                 int trailer_adjust =
437                                         (tie->tim_bitmap+timlen) - (bo->bo_tim_trailer);
438                                 memmove(tie->tim_bitmap+timlen, bo->bo_tim_trailer,
439                                         bo->bo_tim_trailerlen);
440                                 bo->bo_tim_trailer = tie->tim_bitmap+timlen;
441                                 bo->bo_chanswitch += trailer_adjust;
442                                 bo->bo_wme += trailer_adjust;
443                                 bo->bo_erp += trailer_adjust;
444                                 bo->bo_ath_caps += trailer_adjust;
445                                 bo->bo_xr += trailer_adjust;
446                                 if (timlen > bo->bo_tim_len)
447                                         skb_put(skb, timlen - bo->bo_tim_len);
448                                 else
449                                         skb_trim(skb, skb->len - (bo->bo_tim_len - timlen));
450                                 bo->bo_tim_len = timlen;
451
452                                 /* update information element */
453                                 tie->tim_len = 3 + timlen;
454                                 tie->tim_bitctl = timoff;
455                                 len_changed = 1;
456                         }
457                         memcpy(tie->tim_bitmap, vap->iv_tim_bitmap + timoff,
458                                 bo->bo_tim_len);
459
460                         vap->iv_flags &= ~IEEE80211_F_TIMUPDATE;
461
462                         IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
463                                 "%s: TIM updated, pending %u, off %u, len %u",
464                                 __func__, vap->iv_ps_pending, timoff, timlen);
465                 }
466                 /* count down DTIM period */
467                 if (tie->tim_count == 0)
468                         tie->tim_count = tie->tim_period - 1;
469                 else
470                         tie->tim_count--;
471                 /* update state for buffered multicast frames on DTIM */
472                 if (mcast && (tie->tim_count == 0))
473                         tie->tim_bitctl |= 1;
474                 else
475                         tie->tim_bitctl &= ~1;
476
477                 if ((ic->ic_flags & IEEE80211_F_DOTH) &&
478                     (ic->ic_flags & IEEE80211_F_CHANSWITCH)) {
479
480                         if (!vap->iv_chanchange_count) {
481                                 vap->iv_flags |= IEEE80211_F_CHANSWITCH;
482
483                                 /* copy out trailer to open up a slot */
484                                 memmove(bo->bo_chanswitch + IEEE80211_CHANSWITCHANN_BYTES, 
485                                         bo->bo_chanswitch, bo->bo_chanswitch_trailerlen);
486
487                                 /* add ie in opened slot */
488                                 bo->bo_chanswitch[0] = IEEE80211_ELEMID_CHANSWITCHANN;
489                                 bo->bo_chanswitch[1] = 3; /* fixed length */
490                                 bo->bo_chanswitch[2] = 1; /* stas get off for now */
491                                 bo->bo_chanswitch[3] = ic->ic_chanchange_chan;
492                                 bo->bo_chanswitch[4] = ic->ic_chanchange_tbtt;
493
494                                 /* update the trailer lens */
495                                 bo->bo_chanswitch_trailerlen += IEEE80211_CHANSWITCHANN_BYTES;
496                                 bo->bo_tim_trailerlen += IEEE80211_CHANSWITCHANN_BYTES;
497                                 bo->bo_wme += IEEE80211_CHANSWITCHANN_BYTES;
498                                 bo->bo_erp += IEEE80211_CHANSWITCHANN_BYTES;
499                                 bo->bo_ath_caps += IEEE80211_CHANSWITCHANN_BYTES;
500                                 bo->bo_xr += IEEE80211_CHANSWITCHANN_BYTES;
501
502                                 /* indicate new beacon length so other layers may manage memory */
503                                 skb_put(skb, IEEE80211_CHANSWITCHANN_BYTES);
504                                 len_changed = 1;
505                         }
506                         else
507                                 bo->bo_chanswitch[4]--;
508                         vap->iv_chanchange_count++;
509                         IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
510                                 "%s: CHANSWITCH IE, change in %d\n",
511                                 __func__, bo->bo_chanswitch[4]);
512                 }
513 #ifdef ATH_SUPERG_XR
514                 if (vap->iv_flags & IEEE80211_F_XRUPDATE) {
515                         if (vap->iv_xrvap)
516                                 (void) ieee80211_add_xr_param(bo->bo_xr, vap);
517                         vap->iv_flags &= ~IEEE80211_F_XRUPDATE;
518                 }
519 #endif
520                 if (ic->ic_flags_ext & IEEE80211_FEXT_ERPUPDATE) {
521                         (void) ieee80211_add_erp(bo->bo_erp, ic);
522                         ic->ic_flags_ext &= ~IEEE80211_FEXT_ERPUPDATE;
523                 }
524         }
525         /* if it is a mode change beacon for dynamic turbo case */
526         if (((ic->ic_ath_cap & IEEE80211_ATHC_BOOST) != 0) ^
527             IEEE80211_IS_CHAN_TURBO(ic->ic_curchan))
528                 ieee80211_add_athAdvCap(bo->bo_ath_caps, vap->iv_bss->ni_ath_flags,
529                         vap->iv_bss->ni_ath_defkeyindex);
530         /* add APP_IE buffer if app updated it */
531         if (vap->iv_flags_ext & IEEE80211_FEXT_APPIE_UPDATE) {
532                 /* adjust the buffer size if the size is changed */
533                 if (vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length != bo->bo_appie_buf_len) {
534                         int diff_len;
535                         diff_len = vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length - bo->bo_appie_buf_len;
536
537                         if (diff_len > 0)
538                                 skb_put(skb, diff_len);
539                         else
540                                 skb_trim(skb, skb->len + diff_len);
541
542                         bo->bo_appie_buf_len = vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length;
543                         /* update the trailer lens */
544                         bo->bo_chanswitch_trailerlen += diff_len;
545                         bo->bo_tim_trailerlen += diff_len;
546
547                         len_changed = 1;
548                 }
549                 memcpy(bo->bo_appie_buf,vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].ie,
550                         vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length);
551
552                 vap->iv_flags_ext &= ~IEEE80211_FEXT_APPIE_UPDATE;
553         }
554
555         IEEE80211_UNLOCK(ic);
556
557         return len_changed;
558 }
559 EXPORT_SYMBOL(ieee80211_beacon_update);