[svn-upgrade] new version madwifi (0.9.4+r4139.20110504)
[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 4139 2011-05-03 22:07:34Z 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
205         /*
206          * beacon frame format
207          *      [8] time stamp
208          *      [2] beacon interval
209          *      [2] capability information
210          *      [tlv] ssid
211          *      [tlv] supported rates
212          *      [7] FH/DS parameter set
213          *      [tlv] IBSS/TIM parameter set
214          *      [tlv] country code 
215          *      [3] power constraint
216          *      [5] channel switch announcement
217          *      [3] extended rate phy (ERP)
218          *      [tlv] extended supported rates
219          *      [tlv] WME parameters
220          *      [tlv] WPA/RSN parameters
221          *      [tlv] Atheros Advanced Capabilities
222          *      [tlv] AtherosXR parameters
223          * XXX Vendor-specific OIDs (e.g. Atheros)
224          * NB: we allocate the max space required for the TIM bitmap.
225          */
226         pktlen =   8                                    /* time stamp */
227                  + sizeof(u_int16_t)                    /* beacon interval */
228                  + sizeof(u_int16_t)                    /* capability information */
229                  + 2 + ni->ni_esslen                    /* ssid */
230                  + 2 + IEEE80211_RATE_SIZE              /* supported rates */
231                  + 7                                    /* FH/DS parameters max(7,3) */
232                  + 2 + 4 + vap->iv_tim_len              /* IBSS/TIM parameter set*/
233                  + ic->ic_country_ie.country_len + 2    /* country code */
234                  + 3                                    /* power constraint */
235                  + 5                                    /* channel switch announcement */
236                  + 3                                    /* ERP */
237                  + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) /* Ext. Supp. Rates */
238                  + (vap->iv_caps & IEEE80211_C_WME ?    /* WME */
239                         sizeof(struct ieee80211_wme_param) : 0)
240                  + (vap->iv_caps & IEEE80211_C_WPA ?    /* WPA 1+2 */
241                         2 * sizeof(struct ieee80211_ie_wpa) : 0)
242                  + sizeof(struct ieee80211_ie_athAdvCap)
243 #ifdef ATH_SUPERG_XR
244                  + (ic->ic_ath_cap & IEEE80211_ATHC_XR ?        /* XR */
245                         sizeof(struct ieee80211_xr_param) : 0)
246 #endif
247                  ;
248         skb = ieee80211_getmgtframe(&frm, pktlen);
249         if (skb == NULL) {
250                 IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni,
251                         "%s: cannot get buf; size %u", __func__, pktlen);
252                 vap->iv_stats.is_tx_nobuf++;
253                 return NULL;
254         }
255
256         frm = ieee80211_beacon_init(ni, bo, frm);
257
258         skb_trim(skb, frm - skb->data);
259
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_bss->ni_bssid);
269         *(u_int16_t *)wh->i_seq = 0;
270
271         return skb;
272 }
273 EXPORT_SYMBOL(ieee80211_beacon_alloc);
274
275 /*
276  * Update the dynamic parts of a beacon frame based on the current state.
277  */
278 int
279 ieee80211_beacon_update(struct ieee80211_node *ni,
280         struct ieee80211_beacon_offsets *bo, struct sk_buff *skb, int mcast)
281 {
282         struct ieee80211vap *vap = ni->ni_vap;
283         struct ieee80211com *ic = ni->ni_ic;
284         struct ieee80211_frame * wh = (struct ieee80211_frame *) skb->data;
285         int len_changed = 0;
286         u_int16_t capinfo;
287
288         IEEE80211_LOCK(ic);
289
290         /* After an IBSS merge, bssid might have been updated */
291         IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bss->ni_bssid);
292
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             (vap->iv_chanchange_count == ic->ic_chanchange_tbtt)) {
297                 u_int8_t *frm;
298                 struct ieee80211_channel *c;
299
300                 vap->iv_chanchange_count = 0;
301
302                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
303                         "%s: reinit beacon\n", __func__);
304
305                 /* 
306                  * NB: ic_bsschan is in the DSPARMS beacon IE, so must set this
307                  *     prior to the beacon re-init, below.
308                  */
309                 c = ieee80211_doth_findchan(vap, ic->ic_chanchange_chan);
310                 if (c == NULL) {
311                         IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
312                                 "%s: find channel failure\n", __func__);
313                         IEEE80211_UNLOCK(ic);
314                         return 0;
315                 }
316                 ic->ic_bsschan = c;
317
318                 skb_pull(skb, sizeof(struct ieee80211_frame));
319                 skb_trim(skb, 0);
320                 frm = skb->data;
321                 skb_put(skb, ieee80211_beacon_init(ni, bo, frm) - frm); 
322                 skb_push(skb, sizeof(struct ieee80211_frame));
323
324                 vap->iv_flags &= ~IEEE80211_F_CHANSWITCH;
325                 ic->ic_flags &= ~IEEE80211_F_CHANSWITCH;
326
327                 /* NB: only for the first VAP to get here */
328                 if (ic->ic_curchan != c) {
329                         ic->ic_curchan = c;
330                         ic->ic_set_channel(ic);
331                 }
332
333                 len_changed = 1;
334         }
335
336         /* XXX faster to recalculate entirely or just changes? */
337         if (vap->iv_opmode == IEEE80211_M_IBSS)
338                 capinfo = IEEE80211_CAPINFO_IBSS;
339         else
340                 capinfo = IEEE80211_CAPINFO_ESS;
341         if (vap->iv_flags & IEEE80211_F_PRIVACY)
342                 capinfo |= IEEE80211_CAPINFO_PRIVACY;
343         if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
344             IEEE80211_IS_CHAN_2GHZ(ic->ic_bsschan))
345                 capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
346         if (ic->ic_flags & IEEE80211_F_SHSLOT)
347                 capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
348         if (ic->ic_flags & IEEE80211_F_DOTH)
349                 capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT;
350
351         *bo->bo_caps = htole16(capinfo);
352
353         if (vap->iv_flags & IEEE80211_F_WME) {
354                 struct ieee80211_wme_state *wme = &ic->ic_wme;
355
356                 /*
357                  * Check for aggressive mode change.  When there is
358                  * significant high priority traffic in the BSS
359                  * throttle back BE traffic by using conservative
360                  * parameters.  Otherwise BE uses aggressive params
361                  * to optimize performance of legacy/non-QoS traffic.
362                  */
363                 if (wme->wme_flags & WME_F_AGGRMODE) {
364                         if (wme->wme_hipri_traffic >
365                             wme->wme_hipri_switch_thresh) {
366                                 IEEE80211_NOTE(vap, IEEE80211_MSG_WME, ni,
367                                         "%s: traffic %u, disable aggressive mode",
368                                         __func__, wme->wme_hipri_traffic);
369                                 wme->wme_flags &= ~WME_F_AGGRMODE;
370                                 ieee80211_wme_updateparams_locked(vap);
371                                 wme->wme_hipri_traffic =
372                                         wme->wme_hipri_switch_hysteresis;
373                         } else
374                                 wme->wme_hipri_traffic = 0;
375                 } else {
376                         if (wme->wme_hipri_traffic <=
377                             wme->wme_hipri_switch_thresh) {
378                                 IEEE80211_NOTE(vap, IEEE80211_MSG_WME, ni,
379                                         "%s: traffic %u, enable aggressive mode",
380                                         __func__, wme->wme_hipri_traffic);
381                                 wme->wme_flags |= WME_F_AGGRMODE;
382                                 ieee80211_wme_updateparams_locked(vap);
383                                 wme->wme_hipri_traffic = 0;
384                         } else
385                                 wme->wme_hipri_traffic =
386                                         wme->wme_hipri_switch_hysteresis;
387                 }
388                 /* XXX multi-bss */
389                 if (vap->iv_flags & IEEE80211_F_WMEUPDATE) {
390                         (void) ieee80211_add_wme_param(bo->bo_wme, wme, IEEE80211_VAP_UAPSD_ENABLED(vap));
391                         vap->iv_flags &= ~IEEE80211_F_WMEUPDATE;
392                 }
393         }
394
395         if (vap->iv_opmode == IEEE80211_M_HOSTAP) {     /* NB: no IBSS support*/
396                 struct ieee80211_tim_ie *tie =
397                         (struct ieee80211_tim_ie *) bo->bo_tim;
398                 if (vap->iv_flags & IEEE80211_F_TIMUPDATE) {
399                         u_int timlen, timoff, i;
400                         /*
401                          * ATIM/DTIM needs updating.  If it fits in the
402                          * current space allocated then just copy in the
403                          * new bits.  Otherwise we need to move any trailing
404                          * data to make room.  Note that we know there is
405                          * contiguous space because ieee80211_beacon_allocate
406                          * ensures there is space in the mbuf to write a
407                          * maximal-size virtual bitmap (based on ic_max_aid).
408                          */
409                         /*
410                          * Calculate the bitmap size and offset, copy any
411                          * trailer out of the way, and then copy in the
412                          * new bitmap and update the information element.
413                          * Note that the tim bitmap must contain at least
414                          * one byte and any offset must be even.
415                          */
416                         if (vap->iv_ps_pending != 0) {
417                                 timoff = 128;           /* impossibly large */
418                                 for (i = 0; i < vap->iv_tim_len; i++)
419                                         if (vap->iv_tim_bitmap[i]) {
420                                                 timoff = i &~ 1;
421                                                 break;
422                                         }
423                                 KASSERT(timoff != 128, ("tim bitmap empty!"));
424                                 for (i = vap->iv_tim_len-1; i >= timoff; i--)
425                                         if (vap->iv_tim_bitmap[i])
426                                                 break;
427                                 timlen = 1 + (i - timoff);
428                         } else {
429                                 timoff = 0;
430                                 timlen = 1;
431                         }
432                         if (timlen != bo->bo_tim_len) {
433                                 /* copy up/down trailer */
434                                 int trailer_adjust =
435                                         (tie->tim_bitmap+timlen) - (bo->bo_tim_trailer);
436                                 memmove(tie->tim_bitmap+timlen, bo->bo_tim_trailer,
437                                         bo->bo_tim_trailerlen);
438                                 bo->bo_tim_trailer = tie->tim_bitmap+timlen;
439                                 bo->bo_chanswitch += trailer_adjust;
440                                 bo->bo_wme += trailer_adjust;
441                                 bo->bo_erp += trailer_adjust;
442                                 bo->bo_ath_caps += trailer_adjust;
443                                 bo->bo_xr += trailer_adjust;
444                                 if (timlen > bo->bo_tim_len)
445                                         skb_put(skb, timlen - bo->bo_tim_len);
446                                 else
447                                         skb_trim(skb, skb->len - (bo->bo_tim_len - timlen));
448                                 bo->bo_tim_len = timlen;
449
450                                 /* update information element */
451                                 tie->tim_len = 3 + timlen;
452                                 tie->tim_bitctl = timoff;
453                                 len_changed = 1;
454                         }
455                         memcpy(tie->tim_bitmap, vap->iv_tim_bitmap + timoff,
456                                 bo->bo_tim_len);
457
458                         vap->iv_flags &= ~IEEE80211_F_TIMUPDATE;
459
460                         IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
461                                 "%s: TIM updated, pending %u, off %u, len %u",
462                                 __func__, vap->iv_ps_pending, timoff, timlen);
463                 }
464                 /* count down DTIM period */
465                 if (tie->tim_count == 0)
466                         tie->tim_count = tie->tim_period - 1;
467                 else
468                         tie->tim_count--;
469                 /* update state for buffered multicast frames on DTIM */
470                 if (mcast && (tie->tim_count == 0))
471                         tie->tim_bitctl |= 1;
472                 else
473                         tie->tim_bitctl &= ~1;
474
475                 if ((ic->ic_flags & IEEE80211_F_DOTH) &&
476                     (ic->ic_flags & IEEE80211_F_CHANSWITCH)) {
477
478                         if (!vap->iv_chanchange_count) {
479                                 vap->iv_flags |= IEEE80211_F_CHANSWITCH;
480
481                                 /* copy out trailer to open up a slot */
482                                 memmove(bo->bo_chanswitch + IEEE80211_CHANSWITCHANN_BYTES, 
483                                         bo->bo_chanswitch, bo->bo_chanswitch_trailerlen);
484
485                                 /* add ie in opened slot */
486                                 bo->bo_chanswitch[0] = IEEE80211_ELEMID_CHANSWITCHANN;
487                                 bo->bo_chanswitch[1] = 3; /* fixed length */
488                                 bo->bo_chanswitch[2] = 1; /* stas get off for now */
489                                 bo->bo_chanswitch[3] = ic->ic_chanchange_chan;
490                                 bo->bo_chanswitch[4] = ic->ic_chanchange_tbtt;
491
492                                 /* update the trailer lens */
493                                 bo->bo_chanswitch_trailerlen += IEEE80211_CHANSWITCHANN_BYTES;
494                                 bo->bo_tim_trailerlen += IEEE80211_CHANSWITCHANN_BYTES;
495                                 bo->bo_wme += IEEE80211_CHANSWITCHANN_BYTES;
496                                 bo->bo_erp += IEEE80211_CHANSWITCHANN_BYTES;
497                                 bo->bo_ath_caps += IEEE80211_CHANSWITCHANN_BYTES;
498                                 bo->bo_xr += IEEE80211_CHANSWITCHANN_BYTES;
499
500                                 /* indicate new beacon length so other layers may manage memory */
501                                 skb_put(skb, IEEE80211_CHANSWITCHANN_BYTES);
502                                 len_changed = 1;
503                         }
504                         else
505                                 bo->bo_chanswitch[4]--;
506                         vap->iv_chanchange_count++;
507                         IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOTH,
508                                 "%s: CHANSWITCH IE, change in %d\n",
509                                 __func__, bo->bo_chanswitch[4]);
510                 }
511 #ifdef ATH_SUPERG_XR
512                 if (vap->iv_flags & IEEE80211_F_XRUPDATE) {
513                         if (vap->iv_xrvap)
514                                 (void) ieee80211_add_xr_param(bo->bo_xr, vap);
515                         vap->iv_flags &= ~IEEE80211_F_XRUPDATE;
516                 }
517 #endif
518                 if (ic->ic_flags_ext & IEEE80211_FEXT_ERPUPDATE) {
519                         (void) ieee80211_add_erp(bo->bo_erp, ic);
520                         ic->ic_flags_ext &= ~IEEE80211_FEXT_ERPUPDATE;
521                 }
522         }
523         /* if it is a mode change beacon for dynamic turbo case */
524         if (((ic->ic_ath_cap & IEEE80211_ATHC_BOOST) != 0) ^
525             IEEE80211_IS_CHAN_TURBO(ic->ic_curchan))
526                 ieee80211_add_athAdvCap(bo->bo_ath_caps, vap->iv_bss->ni_ath_flags,
527                         vap->iv_bss->ni_ath_defkeyindex);
528         /* add APP_IE buffer if app updated it */
529         if (vap->iv_flags_ext & IEEE80211_FEXT_APPIE_UPDATE) {
530                 /* adjust the buffer size if the size is changed */
531                 if (vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length != bo->bo_appie_buf_len) {
532                         int diff_len;
533                         diff_len = vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length - bo->bo_appie_buf_len;
534
535                         if (diff_len > 0)
536                                 skb_put(skb, diff_len);
537                         else
538                                 skb_trim(skb, skb->len + diff_len);
539
540                         bo->bo_appie_buf_len = vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length;
541                         /* update the trailer lens */
542                         bo->bo_chanswitch_trailerlen += diff_len;
543                         bo->bo_tim_trailerlen += diff_len;
544
545                         len_changed = 1;
546                 }
547                 memcpy(bo->bo_appie_buf,vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].ie,
548                         vap->app_ie[IEEE80211_APPIE_FRAME_BEACON].length);
549
550                 vap->iv_flags_ext &= ~IEEE80211_FEXT_APPIE_UPDATE;
551         }
552
553         IEEE80211_UNLOCK(ic);
554
555         return len_changed;
556 }
557 EXPORT_SYMBOL(ieee80211_beacon_update);