2 * Copyright (c) 2007-2009 Sam Leffler, Errno Consulting
3 * Copyright (c) 2007-2009 Intel Corporation
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.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * $FreeBSD: head/sys/net80211/ieee80211_tdma.c 193114 2009-05-30 19:57:31Z sam $
30 * IEEE 802.11 TDMA mode support.
36 #include <sys/param.h>
37 #include <sys/systm.h>
39 #include <sys/malloc.h>
40 #include <sys/kernel.h>
42 #include <sys/socket.h>
43 #include <sys/sockio.h>
44 #include <sys/endian.h>
45 #include <sys/errno.h>
47 #include <sys/sysctl.h>
50 #include <net/if_media.h>
51 #include <net/if_llc.h>
52 #include <net/ethernet.h>
53 #include <net/route.h>
57 #include <netproto/802_11/ieee80211_var.h>
58 #include <netproto/802_11/ieee80211_tdma.h>
59 #include <netproto/802_11/ieee80211_input.h>
61 #ifndef TDMA_SLOTLEN_DEFAULT
62 #define TDMA_SLOTLEN_DEFAULT 10*1000 /* 10ms */
64 #ifndef TDMA_SLOTCNT_DEFAULT
65 #define TDMA_SLOTCNT_DEFAULT 2 /* 2x (pt-to-pt) */
67 #ifndef TDMA_BINTVAL_DEFAULT
68 #define TDMA_BINTVAL_DEFAULT 5 /* 5x ~= 100TU beacon intvl */
70 #ifndef TDMA_TXRATE_11B_DEFAULT
71 #define TDMA_TXRATE_11B_DEFAULT 2*11
73 #ifndef TDMA_TXRATE_11G_DEFAULT
74 #define TDMA_TXRATE_11G_DEFAULT 2*24
76 #ifndef TDMA_TXRATE_11A_DEFAULT
77 #define TDMA_TXRATE_11A_DEFAULT 2*24
79 #ifndef TDMA_TXRATE_TURBO_DEFAULT
80 #define TDMA_TXRATE_TURBO_DEFAULT 2*24
82 #ifndef TDMA_TXRATE_HALF_DEFAULT
83 #define TDMA_TXRATE_HALF_DEFAULT 2*12
85 #ifndef TDMA_TXRATE_QUARTER_DEFAULT
86 #define TDMA_TXRATE_QUARTER_DEFAULT 2*6
88 #ifndef TDMA_TXRATE_11NA_DEFAULT
89 #define TDMA_TXRATE_11NA_DEFAULT (4 | IEEE80211_RATE_MCS)
91 #ifndef TDMA_TXRATE_11NG_DEFAULT
92 #define TDMA_TXRATE_11NG_DEFAULT (4 | IEEE80211_RATE_MCS)
95 #define TDMA_VERSION_VALID(_version) \
96 (TDMA_VERSION_V2 <= (_version) && (_version) <= TDMA_VERSION)
97 #define TDMA_SLOTCNT_VALID(_slotcnt) \
98 (2 <= (_slotcnt) && (_slotcnt) <= TDMA_MAXSLOTS)
99 /* XXX magic constants */
100 #define TDMA_SLOTLEN_VALID(_slotlen) \
101 (2*100 <= (_slotlen) && (unsigned)(_slotlen) <= 0xfffff)
102 /* XXX probably should set a max */
103 #define TDMA_BINTVAL_VALID(_bintval) (1 <= (_bintval))
106 * This code is not prepared to handle more than 2 slots.
108 CTASSERT(TDMA_MAXSLOTS
== 2);
110 static void tdma_vdetach(struct ieee80211vap
*vap
);
111 static int tdma_newstate(struct ieee80211vap
*, enum ieee80211_state
, int);
112 static void tdma_beacon_miss(struct ieee80211vap
*vap
);
113 static void tdma_recv_mgmt(struct ieee80211_node
*, struct mbuf
*,
114 int subtype
, int rssi
, int nf
);
115 static int tdma_update(struct ieee80211vap
*vap
,
116 const struct ieee80211_tdma_param
*tdma
, struct ieee80211_node
*ni
,
118 static int tdma_process_params(struct ieee80211_node
*ni
,
119 const u_int8_t
*ie
, int rssi
, int nf
, const struct ieee80211_frame
*wh
);
122 settxparms(struct ieee80211vap
*vap
, enum ieee80211_phymode mode
, int rate
)
124 vap
->iv_txparms
[mode
].ucastrate
= rate
;
125 vap
->iv_txparms
[mode
].mcastrate
= rate
;
129 setackpolicy(struct ieee80211com
*ic
, int noack
)
131 struct ieee80211_wme_state
*wme
= &ic
->ic_wme
;
134 for (ac
= 0; ac
< WME_NUM_AC
; ac
++) {
135 wme
->wme_chanParams
.cap_wmeParams
[ac
].wmep_noackPolicy
= noack
;
136 wme
->wme_wmeChanParams
.cap_wmeParams
[ac
].wmep_noackPolicy
= noack
;
141 ieee80211_tdma_vattach(struct ieee80211vap
*vap
)
143 struct ieee80211_tdma_state
*ts
;
145 KASSERT(vap
->iv_caps
& IEEE80211_C_TDMA
,
146 ("not a tdma vap, caps 0x%x", vap
->iv_caps
));
148 ts
= (struct ieee80211_tdma_state
*) kmalloc(
149 sizeof(struct ieee80211_tdma_state
), M_80211_VAP
,
152 kprintf("%s: cannot allocate TDMA state block\n", __func__
);
153 /* NB: fall back to adhdemo mode */
154 vap
->iv_caps
&= ~IEEE80211_C_TDMA
;
157 /* NB: default configuration is passive so no beacons */
158 ts
->tdma_version
= TDMA_VERSION
;
159 ts
->tdma_slotlen
= TDMA_SLOTLEN_DEFAULT
;
160 ts
->tdma_slotcnt
= TDMA_SLOTCNT_DEFAULT
;
161 ts
->tdma_bintval
= TDMA_BINTVAL_DEFAULT
;
162 ts
->tdma_slot
= 1; /* passive operation */
164 /* setup default fixed rates */
165 settxparms(vap
, IEEE80211_MODE_11A
, TDMA_TXRATE_11A_DEFAULT
);
166 settxparms(vap
, IEEE80211_MODE_11B
, TDMA_TXRATE_11B_DEFAULT
);
167 settxparms(vap
, IEEE80211_MODE_11G
, TDMA_TXRATE_11G_DEFAULT
);
168 settxparms(vap
, IEEE80211_MODE_TURBO_A
, TDMA_TXRATE_TURBO_DEFAULT
);
169 settxparms(vap
, IEEE80211_MODE_TURBO_G
, TDMA_TXRATE_TURBO_DEFAULT
);
170 settxparms(vap
, IEEE80211_MODE_STURBO_A
, TDMA_TXRATE_TURBO_DEFAULT
);
171 settxparms(vap
, IEEE80211_MODE_11NA
, TDMA_TXRATE_11NA_DEFAULT
);
172 settxparms(vap
, IEEE80211_MODE_11NG
, TDMA_TXRATE_11NG_DEFAULT
);
173 settxparms(vap
, IEEE80211_MODE_HALF
, TDMA_TXRATE_HALF_DEFAULT
);
174 settxparms(vap
, IEEE80211_MODE_QUARTER
, TDMA_TXRATE_QUARTER_DEFAULT
);
176 setackpolicy(vap
->iv_ic
, 1); /* disable ACK's */
178 ts
->tdma_opdetach
= vap
->iv_opdetach
;
179 vap
->iv_opdetach
= tdma_vdetach
;
180 ts
->tdma_newstate
= vap
->iv_newstate
;
181 vap
->iv_newstate
= tdma_newstate
;
182 vap
->iv_bmiss
= tdma_beacon_miss
;
183 ts
->tdma_recv_mgmt
= vap
->iv_recv_mgmt
;
184 vap
->iv_recv_mgmt
= tdma_recv_mgmt
;
190 tdma_vdetach(struct ieee80211vap
*vap
)
192 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
195 /* NB: should not have touched any ic state */
198 ts
->tdma_opdetach(vap
);
199 kfree(vap
->iv_tdma
, M_80211_VAP
);
202 setackpolicy(vap
->iv_ic
, 0); /* enable ACK's */
206 sta_leave(void *arg
, struct ieee80211_node
*ni
)
208 struct ieee80211vap
*vap
= arg
;
210 if (ni
->ni_vap
== vap
&& ni
!= vap
->iv_bss
)
211 ieee80211_node_leave(ni
);
215 * TDMA state machine handler.
218 tdma_newstate(struct ieee80211vap
*vap
, enum ieee80211_state nstate
, int arg
)
220 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
221 struct ieee80211com
*ic
= vap
->iv_ic
;
222 enum ieee80211_state ostate
;
225 ostate
= vap
->iv_state
;
226 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_STATE
, "%s: %s -> %s (%d)\n",
227 __func__
, ieee80211_state_name
[ostate
],
228 ieee80211_state_name
[nstate
], arg
);
230 if (vap
->iv_flags_ext
& IEEE80211_FEXT_SWBMISS
)
231 callout_stop(&vap
->iv_swbmiss
);
232 if (nstate
== IEEE80211_S_SCAN
&&
233 (ostate
== IEEE80211_S_INIT
|| ostate
== IEEE80211_S_RUN
) &&
234 ts
->tdma_slot
!= 0) {
236 * Override adhoc behaviour when operating as a slave;
237 * we need to scan even if the channel is locked.
239 vap
->iv_state
= nstate
; /* state transition */
240 ieee80211_cancel_scan(vap
); /* background scan */
241 if (ostate
== IEEE80211_S_RUN
) {
242 /* purge station table; entries are stale */
243 ieee80211_iterate_nodes(&ic
->ic_sta
, sta_leave
, vap
);
245 if (vap
->iv_flags_ext
& IEEE80211_FEXT_SCANREQ
) {
246 ieee80211_check_scan(vap
,
247 vap
->iv_scanreq_flags
,
248 vap
->iv_scanreq_duration
,
249 vap
->iv_scanreq_mindwell
,
250 vap
->iv_scanreq_maxdwell
,
251 vap
->iv_scanreq_nssid
, vap
->iv_scanreq_ssid
);
252 vap
->iv_flags_ext
&= ~IEEE80211_FEXT_SCANREQ
;
254 ieee80211_check_scan_current(vap
);
257 status
= ts
->tdma_newstate(vap
, nstate
, arg
);
260 nstate
== IEEE80211_S_RUN
&& ostate
!= IEEE80211_S_RUN
&&
261 (vap
->iv_flags_ext
& IEEE80211_FEXT_SWBMISS
) &&
262 ts
->tdma_slot
!= 0 &&
263 vap
->iv_des_chan
== IEEE80211_CHAN_ANYC
) {
265 * Start s/w beacon miss timer for slave devices w/o
266 * hardware support. Note we do this only if we're
267 * not locked to a channel (i.e. roam to follow the
268 * master). The 2x is a fudge for our doing this in
271 vap
->iv_swbmiss_period
= IEEE80211_TU_TO_TICKS(
272 2 * vap
->iv_bmissthreshold
* ts
->tdma_bintval
*
273 ((ts
->tdma_slotcnt
* ts
->tdma_slotlen
) / 1024));
274 vap
->iv_swbmiss_count
= 0;
275 callout_reset(&vap
->iv_swbmiss
, vap
->iv_swbmiss_period
,
276 ieee80211_swbmiss_callout
, vap
);
282 tdma_beacon_miss(struct ieee80211vap
*vap
)
284 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
286 KASSERT((vap
->iv_ic
->ic_flags
& IEEE80211_F_SCAN
) == 0, ("scanning"));
287 KASSERT(vap
->iv_state
== IEEE80211_S_RUN
,
288 ("wrong state %d", vap
->iv_state
));
290 IEEE80211_DPRINTF(vap
,
291 IEEE80211_MSG_STATE
| IEEE80211_MSG_TDMA
| IEEE80211_MSG_DEBUG
,
292 "beacon miss, mode %u state %s\n",
293 vap
->iv_opmode
, ieee80211_state_name
[vap
->iv_state
]);
295 if (ts
->tdma_peer
!= NULL
) { /* XXX? can this be null? */
296 ieee80211_notify_node_leave(vap
->iv_bss
);
297 ts
->tdma_peer
= NULL
;
299 * Treat beacon miss like an associate failure wrt the
300 * scan policy; this forces the entry in the scan cache
301 * to be ignored after several tries.
303 ieee80211_scan_assoc_fail(vap
, vap
->iv_bss
->ni_macaddr
,
304 IEEE80211_STATUS_TIMEOUT
);
307 ts
->tdma_inuse
= 0; /* clear slot usage */
309 ieee80211_new_state(vap
, IEEE80211_S_SCAN
, 0);
313 tdma_recv_mgmt(struct ieee80211_node
*ni
, struct mbuf
*m0
,
314 int subtype
, int rssi
, int nf
)
316 struct ieee80211com
*ic
= ni
->ni_ic
;
317 struct ieee80211vap
*vap
= ni
->ni_vap
;
318 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
320 if (subtype
== IEEE80211_FC0_SUBTYPE_BEACON
&&
321 (ic
->ic_flags
& IEEE80211_F_SCAN
) == 0) {
322 struct ieee80211_frame
*wh
= mtod(m0
, struct ieee80211_frame
*);
323 struct ieee80211_scanparams scan
;
325 if (ieee80211_parse_beacon(ni
, m0
, &scan
) != 0)
327 if (scan
.tdma
== NULL
) {
329 * TDMA stations must beacon a TDMA ie; ignore
331 * XXX detect overlapping bss and change channel
333 IEEE80211_DISCARD(vap
,
334 IEEE80211_MSG_ELEMID
| IEEE80211_MSG_INPUT
,
335 wh
, ieee80211_mgt_subtype_name
[subtype
>>
336 IEEE80211_FC0_SUBTYPE_SHIFT
],
338 vap
->iv_stats
.is_rx_mgtdiscard
++;
341 if (ni
== vap
->iv_bss
&&
342 !IEEE80211_ADDR_EQ(wh
->i_addr2
, ni
->ni_macaddr
)) {
344 * Fake up a node for this newly
345 * discovered member of the IBSS.
347 ni
= ieee80211_add_neighbor(vap
, wh
, &scan
);
349 /* NB: stat kept for alloc failure */
354 * Check for state updates.
356 if (IEEE80211_ADDR_EQ(wh
->i_addr3
, ni
->ni_bssid
)) {
358 * Count frame now that we know it's to be processed.
360 vap
->iv_stats
.is_rx_beacon
++;
361 IEEE80211_NODE_STAT(ni
, rx_beacons
);
363 * Record tsf of last beacon. NB: this must be
364 * done before calling tdma_process_params
365 * as deeper routines reference it.
367 memcpy(&ni
->ni_tstamp
.data
, scan
.tstamp
,
368 sizeof(ni
->ni_tstamp
.data
));
370 * Count beacon frame for s/w bmiss handling.
372 vap
->iv_swbmiss_count
++;
374 * Process tdma ie. The contents are used to sync
375 * the slot timing, reconfigure the bss, etc.
377 (void) tdma_process_params(ni
, scan
.tdma
, rssi
, nf
, wh
);
381 * NB: defer remaining work to the adhoc code; this causes
382 * 2x parsing of the frame but should happen infrequently
385 ts
->tdma_recv_mgmt(ni
, m0
, subtype
, rssi
, nf
);
389 * Update TDMA state on receipt of a beacon frame with
390 * a TDMA information element. The sender's identity
391 * is provided so we can track who our peer is. If pickslot
392 * is non-zero we scan the slot allocation state in the ie
393 * to locate a free slot for our use.
396 tdma_update(struct ieee80211vap
*vap
, const struct ieee80211_tdma_param
*tdma
,
397 struct ieee80211_node
*ni
, int pickslot
)
399 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
400 int slot
, slotlen
, update
;
402 KASSERT(vap
->iv_caps
& IEEE80211_C_TDMA
,
403 ("not a tdma vap, caps 0x%x", vap
->iv_caps
));
406 if (tdma
->tdma_slotcnt
!= ts
->tdma_slotcnt
) {
407 if (!TDMA_SLOTCNT_VALID(tdma
->tdma_slotcnt
)) {
408 if (ppsratecheck(&ts
->tdma_lastprint
, &ts
->tdma_fails
, 1))
409 kprintf("%s: bad slot cnt %u\n",
410 __func__
, tdma
->tdma_slotcnt
);
413 update
|= TDMA_UPDATE_SLOTCNT
;
415 slotlen
= le16toh(tdma
->tdma_slotlen
) * 100;
416 if (slotlen
!= ts
->tdma_slotlen
) {
417 if (!TDMA_SLOTLEN_VALID(slotlen
)) {
418 if (ppsratecheck(&ts
->tdma_lastprint
, &ts
->tdma_fails
, 1))
419 kprintf("%s: bad slot len %u\n",
423 update
|= TDMA_UPDATE_SLOTLEN
;
425 if (tdma
->tdma_bintval
!= ts
->tdma_bintval
) {
426 if (!TDMA_BINTVAL_VALID(tdma
->tdma_bintval
)) {
427 if (ppsratecheck(&ts
->tdma_lastprint
, &ts
->tdma_fails
, 1))
428 kprintf("%s: bad beacon interval %u\n",
429 __func__
, tdma
->tdma_bintval
);
432 update
|= TDMA_UPDATE_BINTVAL
;
434 slot
= ts
->tdma_slot
;
437 * Pick unoccupied slot. Note we never choose slot 0.
439 for (slot
= tdma
->tdma_slotcnt
-1; slot
> 0; slot
--)
440 if (isclr(tdma
->tdma_inuse
, slot
))
443 kprintf("%s: no free slot, slotcnt %u inuse: 0x%x\n",
444 __func__
, tdma
->tdma_slotcnt
,
445 tdma
->tdma_inuse
[0]);
446 /* XXX need to do something better */
449 if (slot
!= ts
->tdma_slot
)
450 update
|= TDMA_UPDATE_SLOT
;
452 if (ni
!= ts
->tdma_peer
) {
453 /* update everything */
454 update
= TDMA_UPDATE_SLOT
455 | TDMA_UPDATE_SLOTCNT
456 | TDMA_UPDATE_SLOTLEN
457 | TDMA_UPDATE_BINTVAL
;
462 * New/changed parameters; update runtime state.
464 /* XXX overwrites user parameters */
465 if (update
& TDMA_UPDATE_SLOTCNT
)
466 ts
->tdma_slotcnt
= tdma
->tdma_slotcnt
;
467 if (update
& TDMA_UPDATE_SLOTLEN
)
468 ts
->tdma_slotlen
= slotlen
;
469 if (update
& TDMA_UPDATE_SLOT
)
470 ts
->tdma_slot
= slot
;
471 if (update
& TDMA_UPDATE_BINTVAL
)
472 ts
->tdma_bintval
= tdma
->tdma_bintval
;
473 /* mark beacon to be updated before next xmit */
474 ieee80211_beacon_notify(vap
, IEEE80211_BEACON_TDMA
);
476 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_TDMA
,
477 "%s: slot %u slotcnt %u slotlen %u us bintval %u\n",
478 __func__
, ts
->tdma_slot
, ts
->tdma_slotcnt
,
479 ts
->tdma_slotlen
, ts
->tdma_bintval
);
482 * Notify driver. Note we can be called before
483 * entering RUN state if we scanned and are
484 * joining an existing bss. In that case do not
485 * call the driver because not all necessary state
486 * has been setup. The next beacon will dtrt.
488 if (vap
->iv_state
== IEEE80211_S_RUN
)
489 vap
->iv_ic
->ic_tdma_update(ni
, tdma
, update
);
491 * Dispatch join event on first beacon from new master.
493 if (ts
->tdma_peer
!= ni
) {
494 if (ts
->tdma_peer
!= NULL
)
495 ieee80211_notify_node_leave(vap
->iv_bss
);
496 ieee80211_notify_node_join(ni
, 1);
497 /* NB: no reference, we just use the address */
504 * Process received TDMA parameters.
507 tdma_process_params(struct ieee80211_node
*ni
, const u_int8_t
*ie
,
508 int rssi
, int nf
, const struct ieee80211_frame
*wh
)
510 struct ieee80211vap
*vap
= ni
->ni_vap
;
511 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
512 const struct ieee80211_tdma_param
*tdma
=
513 (const struct ieee80211_tdma_param
*) ie
;
516 KASSERT(vap
->iv_caps
& IEEE80211_C_TDMA
,
517 ("not a tdma vap, caps 0x%x", vap
->iv_caps
));
519 if (len
< sizeof(*tdma
) - 2) {
520 IEEE80211_DISCARD_IE(vap
,
521 IEEE80211_MSG_ELEMID
| IEEE80211_MSG_TDMA
,
522 wh
, "tdma", "too short, len %u", len
);
523 return IEEE80211_REASON_IE_INVALID
;
525 if (tdma
->tdma_version
!= ts
->tdma_version
) {
526 IEEE80211_DISCARD_IE(vap
,
527 IEEE80211_MSG_ELEMID
| IEEE80211_MSG_TDMA
,
528 wh
, "tdma", "bad version %u (ours %u)",
529 tdma
->tdma_version
, ts
->tdma_version
);
530 return IEEE80211_REASON_IE_INVALID
;
533 * NB: ideally we'd check against tdma_slotcnt, but that
534 * would require extra effort so do this easy check that
535 * covers the work below; more stringent checks are done
536 * before we make more extensive use of the ie contents.
538 if (tdma
->tdma_slot
>= TDMA_MAXSLOTS
) {
539 IEEE80211_DISCARD_IE(vap
,
540 IEEE80211_MSG_ELEMID
| IEEE80211_MSG_TDMA
,
541 wh
, "tdma", "invalid slot %u", tdma
->tdma_slot
);
542 return IEEE80211_REASON_IE_INVALID
;
545 * Can reach here while scanning, update
546 * operational state only in RUN state.
548 if (vap
->iv_state
== IEEE80211_S_RUN
) {
549 if (tdma
->tdma_slot
!= ts
->tdma_slot
&&
550 isclr(ts
->tdma_inuse
, tdma
->tdma_slot
)) {
551 IEEE80211_NOTE(vap
, IEEE80211_MSG_TDMA
, ni
,
552 "discovered in slot %u", tdma
->tdma_slot
);
553 setbit(ts
->tdma_inuse
, tdma
->tdma_slot
);
554 /* XXX dispatch event only when operating as master */
555 if (ts
->tdma_slot
== 0)
556 ieee80211_notify_node_join(ni
, 1);
558 setbit(ts
->tdma_active
, tdma
->tdma_slot
);
559 if (tdma
->tdma_slot
== ts
->tdma_slot
-1) {
561 * Slave tsf synchronization to station
562 * just before us in the schedule. The driver
563 * is responsible for copying the timestamp
564 * of the received beacon into our beacon
565 * frame so the sender can calculate round
566 * trip time. We cannot do that here because
567 * we don't know how to update our beacon frame.
569 (void) tdma_update(vap
, tdma
, ni
, 0);
570 /* XXX reschedule swbmiss timer on parameter change */
571 } else if (tdma
->tdma_slot
== ts
->tdma_slot
+1) {
574 uint32_t rstamp
= (uint32_t) le64toh(rs
->tsf
);
578 * Use returned timstamp to calculate the
581 memcpy(&tstamp
, tdma
->tdma_tstamp
, 8);
583 /* XXX use only 15 bits of rstamp */
584 rtt
= rstamp
- (le64toh(tstamp
) & 0x7fff);
587 /* XXX hack to quiet normal use */
588 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_DOT1X
,
589 "tdma rtt %5u [rstamp %5u tstamp %llu]\n",
591 (unsigned long long) le64toh(tstamp
));
593 } else if (tdma
->tdma_slot
== ts
->tdma_slot
&&
594 le64toh(ni
->ni_tstamp
.tsf
) > vap
->iv_bss
->ni_tstamp
.tsf
) {
596 * Station using the same slot as us and has
597 * been around longer than us; we must move.
598 * Note this can happen if stations do not
599 * see each other while scanning.
601 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_TDMA
,
602 "slot %u collision rxtsf %llu tsf %llu\n",
604 (unsigned long long) le64toh(ni
->ni_tstamp
.tsf
),
605 (unsigned long long)vap
->iv_bss
->ni_tstamp
.tsf
);
606 setbit(ts
->tdma_inuse
, tdma
->tdma_slot
);
608 (void) tdma_update(vap
, tdma
, ni
, 1);
615 ieee80211_tdma_getslot(struct ieee80211vap
*vap
)
617 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
619 KASSERT(vap
->iv_caps
& IEEE80211_C_TDMA
,
620 ("not a tdma vap, caps 0x%x", vap
->iv_caps
));
621 return ts
->tdma_slot
;
625 * Parse a TDMA ie on station join and use it to setup node state.
628 ieee80211_parse_tdma(struct ieee80211_node
*ni
, const uint8_t *ie
)
630 struct ieee80211vap
*vap
= ni
->ni_vap
;
632 if (vap
->iv_caps
& IEEE80211_C_TDMA
) {
633 const struct ieee80211_tdma_param
*tdma
=
634 (const struct ieee80211_tdma_param
*)ie
;
635 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
637 * Adopt TDMA configuration when joining an
640 setbit(ts
->tdma_inuse
, tdma
->tdma_slot
);
641 (void) tdma_update(vap
, tdma
, ni
, 1);
643 * Propagate capabilities based on the local
644 * configuration and the remote station's advertised
645 * capabilities. In particular this permits us to
646 * enable use of QoS to disable ACK's.
648 if ((vap
->iv_flags
& IEEE80211_F_WME
) &&
649 ni
->ni_ies
.wme_ie
!= NULL
)
650 ni
->ni_flags
|= IEEE80211_NODE_QOS
;
654 #define TDMA_OUI_BYTES 0x00, 0x03, 0x7f
656 * Add a TDMA parameters element to a frame.
659 ieee80211_add_tdma(uint8_t *frm
, struct ieee80211vap
*vap
)
661 #define ADDSHORT(frm, v) do { \
662 frm[0] = (v) & 0xff; \
666 static const struct ieee80211_tdma_param param
= {
667 .tdma_id
= IEEE80211_ELEMID_VENDOR
,
668 .tdma_len
= sizeof(struct ieee80211_tdma_param
) - 2,
669 .tdma_oui
= { TDMA_OUI_BYTES
},
670 .tdma_type
= TDMA_OUI_TYPE
,
671 .tdma_subtype
= TDMA_SUBTYPE_PARAM
,
672 .tdma_version
= TDMA_VERSION
,
674 const struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
677 KASSERT(vap
->iv_caps
& IEEE80211_C_TDMA
,
678 ("not a tdma vap, caps 0x%x", vap
->iv_caps
));
680 memcpy(frm
, ¶m
, sizeof(param
));
681 frm
+= __offsetof(struct ieee80211_tdma_param
, tdma_slot
);
682 *frm
++ = ts
->tdma_slot
;
683 *frm
++ = ts
->tdma_slotcnt
;
684 /* NB: convert units to fit in 16-bits */
685 slotlen
= ts
->tdma_slotlen
/ 100; /* 100us units */
686 ADDSHORT(frm
, slotlen
);
687 *frm
++ = ts
->tdma_bintval
;
688 *frm
++ = ts
->tdma_inuse
[0];
689 frm
+= 10; /* pad+timestamp */
693 #undef TDMA_OUI_BYTES
696 * Update TDMA state at TBTT.
699 ieee80211_tdma_update_beacon(struct ieee80211vap
*vap
,
700 struct ieee80211_beacon_offsets
*bo
)
702 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
704 KASSERT(vap
->iv_caps
& IEEE80211_C_TDMA
,
705 ("not a tdma vap, caps 0x%x", vap
->iv_caps
));
707 if (isset(bo
->bo_flags
, IEEE80211_BEACON_TDMA
)) {
708 (void) ieee80211_add_tdma(bo
->bo_tdma
, vap
);
709 clrbit(bo
->bo_flags
, IEEE80211_BEACON_TDMA
);
711 if (ts
->tdma_slot
!= 0) /* only on master */
713 if (ts
->tdma_count
<= 0) {
715 * Time to update the mask of active/inuse stations.
716 * We track stations that we've received a beacon
717 * frame from and update this mask periodically.
718 * This allows us to miss a few beacons before marking
719 * a slot free for re-use.
721 ts
->tdma_inuse
[0] = ts
->tdma_active
[0];
722 ts
->tdma_active
[0] = 0x01;
723 /* update next time 'round */
724 /* XXX use notify framework */
725 setbit(bo
->bo_flags
, IEEE80211_BEACON_TDMA
);
726 /* NB: use s/w beacon miss threshold; may be too high */
727 ts
->tdma_count
= vap
->iv_bmissthreshold
-1;
733 tdma_ioctl_get80211(struct ieee80211vap
*vap
, struct ieee80211req
*ireq
)
735 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
737 if ((vap
->iv_caps
& IEEE80211_C_TDMA
) == 0)
740 switch (ireq
->i_type
) {
741 case IEEE80211_IOC_TDMA_SLOT
:
742 ireq
->i_val
= ts
->tdma_slot
;
744 case IEEE80211_IOC_TDMA_SLOTCNT
:
745 ireq
->i_val
= ts
->tdma_slotcnt
;
747 case IEEE80211_IOC_TDMA_SLOTLEN
:
748 ireq
->i_val
= ts
->tdma_slotlen
;
750 case IEEE80211_IOC_TDMA_BINTERVAL
:
751 ireq
->i_val
= ts
->tdma_bintval
;
758 IEEE80211_IOCTL_GET(tdma
, tdma_ioctl_get80211
);
761 tdma_ioctl_set80211(struct ieee80211vap
*vap
, struct ieee80211req
*ireq
)
763 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
765 if ((vap
->iv_caps
& IEEE80211_C_TDMA
) == 0)
768 switch (ireq
->i_type
) {
769 case IEEE80211_IOC_TDMA_SLOT
:
770 if (!(0 <= ireq
->i_val
&& ireq
->i_val
<= ts
->tdma_slotcnt
))
772 if (ireq
->i_val
!= ts
->tdma_slot
) {
773 ts
->tdma_slot
= ireq
->i_val
;
777 case IEEE80211_IOC_TDMA_SLOTCNT
:
778 if (!TDMA_SLOTCNT_VALID(ireq
->i_val
))
780 if (ireq
->i_val
!= ts
->tdma_slotcnt
) {
781 ts
->tdma_slotcnt
= ireq
->i_val
;
785 case IEEE80211_IOC_TDMA_SLOTLEN
:
788 * 150 insures at least 1/8 TU
789 * 0xfffff is the max duration for bursting
790 * (implict by way of 16-bit data type for i_val)
792 if (!TDMA_SLOTLEN_VALID(ireq
->i_val
))
794 if (ireq
->i_val
!= ts
->tdma_slotlen
) {
795 ts
->tdma_slotlen
= ireq
->i_val
;
799 case IEEE80211_IOC_TDMA_BINTERVAL
:
800 if (!TDMA_BINTVAL_VALID(ireq
->i_val
))
802 if (ireq
->i_val
!= ts
->tdma_bintval
) {
803 ts
->tdma_bintval
= ireq
->i_val
;
812 ieee80211_beacon_notify(vap
, IEEE80211_BEACON_TDMA
);
815 IEEE80211_IOCTL_SET(tdma
, tdma_ioctl_set80211
);