2 * Copyright (c) 2001 Atsushi Onoe
3 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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 $
39 * IEEE 802.11 beacon handling routines
41 #ifndef AUTOCONF_INCLUDED
42 #include <linux/config.h>
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>
51 #include <net80211/ieee80211_var.h>
55 ieee80211_beacon_init(struct ieee80211_node
*ni
, struct ieee80211_beacon_offsets
*bo
,
58 struct ieee80211vap
*vap
= ni
->ni_vap
;
59 struct ieee80211com
*ic
= ni
->ni_ic
;
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 */
70 *(__le16
*)frm
= htole16(ni
->ni_intval
);
73 /* capability information */
74 if (vap
->iv_opmode
== IEEE80211_M_IBSS
)
75 capinfo
= IEEE80211_CAPINFO_IBSS
;
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
);
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
);
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
;
109 *frm
++ = ieee80211_chan2ieee(ic
, ic
->ic_bsschan
);
114 if (vap
->iv_opmode
== IEEE80211_M_IBSS
) {
115 *frm
++ = IEEE80211_ELEMID_IBSSPARMS
;
117 *frm
++ = 0; *frm
++ = 0; /* TODO: ATIM window */
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
);
131 bo
->bo_tim_trailer
= frm
;
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
;
146 if (IEEE80211_IS_CHAN_ANYG(ic
->ic_bsschan
)) {
148 frm
= ieee80211_add_erp(frm
, ic
);
151 /* Ext. Supp. Rates */
152 frm
= ieee80211_add_xrates(frm
, rs
);
155 if (vap
->iv_flags
& IEEE80211_F_WME
) {
157 frm
= ieee80211_add_wme_param(frm
, &ic
->ic_wme
, IEEE80211_VAP_UAPSD_ENABLED(vap
));
158 vap
->iv_flags
&= ~IEEE80211_F_WMEUPDATE
;
162 if (vap
->iv_flags
& IEEE80211_F_WPA
)
163 frm
= ieee80211_add_wpa(frm
, vap
);
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
);
174 if (vap
->iv_xrvap
&& vap
->iv_ath_cap
& IEEE80211_ATHC_XR
) /* XR */
175 frm
= ieee80211_add_xr_param(frm
, vap
);
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
;
188 * Allocate a beacon frame and fillin the appropriate bits.
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
;
200 struct ieee80211_rateset
*rs
;
203 * beacon frame format
205 * [2] beacon interval
206 * [2] capability information
208 * [tlv] supported rates
209 * [7] FH/DS parameter set
210 * [tlv] IBSS/TIM parameter set
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.
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 */
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
)
242 + (ic
->ic_ath_cap
& IEEE80211_ATHC_XR
? /* XR */
243 sizeof(struct ieee80211_xr_param
) : 0)
246 skb
= ieee80211_getmgtframe(&frm
, pktlen
);
248 IEEE80211_NOTE(vap
, IEEE80211_MSG_ANY
, ni
,
249 "%s: cannot get buf; size %u", __func__
, pktlen
);
250 vap
->iv_stats
.is_tx_nobuf
++;
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
;
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;
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
;
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
))) {
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. */
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__
);
320 skb_pull(skb
, sizeof(struct ieee80211_frame
));
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
)) {
334 ic
->ic_set_channel(ic
);
341 /* XXX faster to recalculate entirely or just changes? */
342 if (vap
->iv_opmode
== IEEE80211_M_IBSS
)
343 capinfo
= IEEE80211_CAPINFO_IBSS
;
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
;
380 wme
->wme_hipri_traffic
= 0;
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;
391 wme
->wme_hipri_traffic
=
392 wme
->wme_hipri_switch_hysteresis
;
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
;
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
])
433 timlen
= 1 + (i
- timoff
);
438 if (timlen
!= bo
->bo_tim_len
) {
439 /* copy up/down trailer */
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
);
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
;
461 memcpy(tie
->tim_bitmap
, vap
->iv_tim_bitmap
+ timoff
,
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;
475 /* update state for buffered multicast frames on DTIM */
476 if (mcast
&& (tie
->tim_count
== 0))
477 tie
->tim_bitctl
|= BITCTL_BUFD_MCAST
;
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
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: "
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
),
509 bo
->bo_chanswitch_trailerlen
);
511 /* add ie in opened slot */
512 csa_ie
->csa_id
= IEEE80211_ELEMID_CHANSWITCHANN
;
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
));
532 } else if (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
);
541 if (vap
->iv_flags
& IEEE80211_F_XRUPDATE
) {
543 (void)ieee80211_add_xr_param(bo
->bo_xr
, vap
);
544 vap
->iv_flags
&= ~IEEE80211_F_XRUPDATE
;
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
) {
566 vap
->app_ie
[IEEE80211_APPIE_FRAME_BEACON
].
568 bo
->bo_appie_buf_len
;
571 skb_put(skb
, diff_len
);
573 skb_trim(skb
, skb
->len
+ diff_len
);
575 bo
->bo_appie_buf_len
=
576 vap
->app_ie
[IEEE80211_APPIE_FRAME_BEACON
].
578 /* update the trailer lens */
579 bo
->bo_chanswitch_trailerlen
+= diff_len
;
580 bo
->bo_tim_trailerlen
+= diff_len
;
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
);
595 EXPORT_SYMBOL(ieee80211_beacon_update
);