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.
27 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
33 * IEEE 802.11 TDMA mode support.
39 #include <sys/param.h>
40 #include <sys/systm.h>
42 #include <sys/malloc.h>
43 #include <sys/kernel.h>
45 #include <sys/socket.h>
46 #include <sys/sockio.h>
47 #include <sys/endian.h>
48 #include <sys/errno.h>
50 #include <sys/sysctl.h>
53 #include <net/if_media.h>
54 #include <net/if_llc.h>
55 #include <net/ethernet.h>
59 #include <net80211/ieee80211_var.h>
60 #include <net80211/ieee80211_tdma.h>
61 #include <net80211/ieee80211_input.h>
63 #ifndef TDMA_SLOTLEN_DEFAULT
64 #define TDMA_SLOTLEN_DEFAULT 10*1000 /* 10ms */
66 #ifndef TDMA_SLOTCNT_DEFAULT
67 #define TDMA_SLOTCNT_DEFAULT 2 /* 2x (pt-to-pt) */
69 #ifndef TDMA_BINTVAL_DEFAULT
70 #define TDMA_BINTVAL_DEFAULT 5 /* 5x ~= 100TU beacon intvl */
72 #ifndef TDMA_TXRATE_11B_DEFAULT
73 #define TDMA_TXRATE_11B_DEFAULT 2*11
75 #ifndef TDMA_TXRATE_11G_DEFAULT
76 #define TDMA_TXRATE_11G_DEFAULT 2*24
78 #ifndef TDMA_TXRATE_11A_DEFAULT
79 #define TDMA_TXRATE_11A_DEFAULT 2*24
81 #ifndef TDMA_TXRATE_TURBO_DEFAULT
82 #define TDMA_TXRATE_TURBO_DEFAULT 2*24
84 #ifndef TDMA_TXRATE_HALF_DEFAULT
85 #define TDMA_TXRATE_HALF_DEFAULT 2*12
87 #ifndef TDMA_TXRATE_QUARTER_DEFAULT
88 #define TDMA_TXRATE_QUARTER_DEFAULT 2*6
90 #ifndef TDMA_TXRATE_11NA_DEFAULT
91 #define TDMA_TXRATE_11NA_DEFAULT (4 | IEEE80211_RATE_MCS)
93 #ifndef TDMA_TXRATE_11NG_DEFAULT
94 #define TDMA_TXRATE_11NG_DEFAULT (4 | IEEE80211_RATE_MCS)
97 #define TDMA_VERSION_VALID(_version) \
98 (TDMA_VERSION_V2 <= (_version) && (_version) <= TDMA_VERSION)
99 #define TDMA_SLOTCNT_VALID(_slotcnt) \
100 (2 <= (_slotcnt) && (_slotcnt) <= TDMA_MAXSLOTS)
101 /* XXX magic constants */
102 #define TDMA_SLOTLEN_VALID(_slotlen) \
103 (2*100 <= (_slotlen) && (unsigned)(_slotlen) <= 0xfffff)
104 /* XXX probably should set a max */
105 #define TDMA_BINTVAL_VALID(_bintval) (1 <= (_bintval))
108 * This code is not prepared to handle more than 2 slots.
110 CTASSERT(TDMA_MAXSLOTS
== 2);
112 static void tdma_vdetach(struct ieee80211vap
*vap
);
113 static int tdma_newstate(struct ieee80211vap
*, enum ieee80211_state
, int);
114 static void tdma_beacon_miss(struct ieee80211vap
*vap
);
115 static void tdma_recv_mgmt(struct ieee80211_node
*, struct mbuf
*,
116 int subtype
, int rssi
, int nf
);
117 static int tdma_update(struct ieee80211vap
*vap
,
118 const struct ieee80211_tdma_param
*tdma
, struct ieee80211_node
*ni
,
120 static int tdma_process_params(struct ieee80211_node
*ni
,
121 const u_int8_t
*ie
, int rssi
, int nf
, const struct ieee80211_frame
*wh
);
124 settxparms(struct ieee80211vap
*vap
, enum ieee80211_phymode mode
, int rate
)
126 vap
->iv_txparms
[mode
].ucastrate
= rate
;
127 vap
->iv_txparms
[mode
].mcastrate
= rate
;
131 setackpolicy(struct ieee80211com
*ic
, int noack
)
133 struct ieee80211_wme_state
*wme
= &ic
->ic_wme
;
136 for (ac
= 0; ac
< WME_NUM_AC
; ac
++) {
137 wme
->wme_chanParams
.cap_wmeParams
[ac
].wmep_noackPolicy
= noack
;
138 wme
->wme_wmeChanParams
.cap_wmeParams
[ac
].wmep_noackPolicy
= noack
;
143 ieee80211_tdma_vattach(struct ieee80211vap
*vap
)
145 struct ieee80211_tdma_state
*ts
;
147 KASSERT(vap
->iv_caps
& IEEE80211_C_TDMA
,
148 ("not a tdma vap, caps 0x%x", vap
->iv_caps
));
150 ts
= (struct ieee80211_tdma_state
*) malloc(
151 sizeof(struct ieee80211_tdma_state
), M_80211_VAP
, M_NOWAIT
| M_ZERO
);
153 printf("%s: cannot allocate TDMA state block\n", __func__
);
154 /* NB: fall back to adhdemo mode */
155 vap
->iv_caps
&= ~IEEE80211_C_TDMA
;
158 /* NB: default configuration is passive so no beacons */
159 ts
->tdma_version
= TDMA_VERSION
;
160 ts
->tdma_slotlen
= TDMA_SLOTLEN_DEFAULT
;
161 ts
->tdma_slotcnt
= TDMA_SLOTCNT_DEFAULT
;
162 ts
->tdma_bintval
= TDMA_BINTVAL_DEFAULT
;
163 ts
->tdma_slot
= 1; /* passive operation */
165 /* setup default fixed rates */
166 settxparms(vap
, IEEE80211_MODE_11A
, TDMA_TXRATE_11A_DEFAULT
);
167 settxparms(vap
, IEEE80211_MODE_11B
, TDMA_TXRATE_11B_DEFAULT
);
168 settxparms(vap
, IEEE80211_MODE_11G
, TDMA_TXRATE_11G_DEFAULT
);
169 settxparms(vap
, IEEE80211_MODE_TURBO_A
, TDMA_TXRATE_TURBO_DEFAULT
);
170 settxparms(vap
, IEEE80211_MODE_TURBO_G
, TDMA_TXRATE_TURBO_DEFAULT
);
171 settxparms(vap
, IEEE80211_MODE_STURBO_A
, TDMA_TXRATE_TURBO_DEFAULT
);
172 settxparms(vap
, IEEE80211_MODE_11NA
, TDMA_TXRATE_11NA_DEFAULT
);
173 settxparms(vap
, IEEE80211_MODE_11NG
, TDMA_TXRATE_11NG_DEFAULT
);
174 settxparms(vap
, IEEE80211_MODE_HALF
, TDMA_TXRATE_HALF_DEFAULT
);
175 settxparms(vap
, IEEE80211_MODE_QUARTER
, TDMA_TXRATE_QUARTER_DEFAULT
);
177 setackpolicy(vap
->iv_ic
, 1); /* disable ACK's */
179 ts
->tdma_opdetach
= vap
->iv_opdetach
;
180 vap
->iv_opdetach
= tdma_vdetach
;
181 ts
->tdma_newstate
= vap
->iv_newstate
;
182 vap
->iv_newstate
= tdma_newstate
;
183 vap
->iv_bmiss
= tdma_beacon_miss
;
184 ts
->tdma_recv_mgmt
= vap
->iv_recv_mgmt
;
185 vap
->iv_recv_mgmt
= tdma_recv_mgmt
;
191 tdma_vdetach(struct ieee80211vap
*vap
)
193 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
196 /* NB: should not have touched any ic state */
199 ts
->tdma_opdetach(vap
);
200 free(vap
->iv_tdma
, M_80211_VAP
);
203 setackpolicy(vap
->iv_ic
, 0); /* enable ACK's */
207 sta_leave(void *arg
, struct ieee80211_node
*ni
)
209 struct ieee80211vap
*vap
= arg
;
211 if (ni
->ni_vap
== vap
&& ni
!= vap
->iv_bss
)
212 ieee80211_node_leave(ni
);
216 * TDMA state machine handler.
219 tdma_newstate(struct ieee80211vap
*vap
, enum ieee80211_state nstate
, int arg
)
221 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
222 struct ieee80211com
*ic
= vap
->iv_ic
;
223 enum ieee80211_state ostate
;
226 IEEE80211_LOCK_ASSERT(ic
);
228 ostate
= vap
->iv_state
;
229 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_STATE
, "%s: %s -> %s (%d)\n",
230 __func__
, ieee80211_state_name
[ostate
],
231 ieee80211_state_name
[nstate
], arg
);
233 if (vap
->iv_flags_ext
& IEEE80211_FEXT_SWBMISS
)
234 callout_stop(&vap
->iv_swbmiss
);
235 if (nstate
== IEEE80211_S_SCAN
&&
236 (ostate
== IEEE80211_S_INIT
|| ostate
== IEEE80211_S_RUN
) &&
237 ts
->tdma_slot
!= 0) {
239 * Override adhoc behaviour when operating as a slave;
240 * we need to scan even if the channel is locked.
242 vap
->iv_state
= nstate
; /* state transition */
243 ieee80211_cancel_scan(vap
); /* background scan */
244 if (ostate
== IEEE80211_S_RUN
) {
245 /* purge station table; entries are stale */
246 ieee80211_iterate_nodes(&ic
->ic_sta
, sta_leave
, vap
);
248 if (vap
->iv_flags_ext
& IEEE80211_FEXT_SCANREQ
) {
249 ieee80211_check_scan(vap
,
250 vap
->iv_scanreq_flags
,
251 vap
->iv_scanreq_duration
,
252 vap
->iv_scanreq_mindwell
,
253 vap
->iv_scanreq_maxdwell
,
254 vap
->iv_scanreq_nssid
, vap
->iv_scanreq_ssid
);
255 vap
->iv_flags_ext
&= ~IEEE80211_FEXT_SCANREQ
;
257 ieee80211_check_scan_current(vap
);
260 status
= ts
->tdma_newstate(vap
, nstate
, arg
);
263 nstate
== IEEE80211_S_RUN
&& ostate
!= IEEE80211_S_RUN
&&
264 (vap
->iv_flags_ext
& IEEE80211_FEXT_SWBMISS
) &&
265 ts
->tdma_slot
!= 0 &&
266 vap
->iv_des_chan
== IEEE80211_CHAN_ANYC
) {
268 * Start s/w beacon miss timer for slave devices w/o
269 * hardware support. Note we do this only if we're
270 * not locked to a channel (i.e. roam to follow the
271 * master). The 2x is a fudge for our doing this in
274 vap
->iv_swbmiss_period
= IEEE80211_TU_TO_TICKS(
275 2 * vap
->iv_bmissthreshold
* ts
->tdma_bintval
*
276 ((ts
->tdma_slotcnt
* ts
->tdma_slotlen
) / 1024));
277 vap
->iv_swbmiss_count
= 0;
278 callout_reset(&vap
->iv_swbmiss
, vap
->iv_swbmiss_period
,
279 ieee80211_swbmiss
, vap
);
285 tdma_beacon_miss(struct ieee80211vap
*vap
)
287 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
289 KASSERT((vap
->iv_ic
->ic_flags
& IEEE80211_F_SCAN
) == 0, ("scanning"));
290 KASSERT(vap
->iv_state
== IEEE80211_S_RUN
,
291 ("wrong state %d", vap
->iv_state
));
293 IEEE80211_DPRINTF(vap
,
294 IEEE80211_MSG_STATE
| IEEE80211_MSG_TDMA
| IEEE80211_MSG_DEBUG
,
295 "beacon miss, mode %u state %s\n",
296 vap
->iv_opmode
, ieee80211_state_name
[vap
->iv_state
]);
298 callout_stop(&vap
->iv_swbmiss
);
300 if (ts
->tdma_peer
!= NULL
) { /* XXX? can this be null? */
301 ieee80211_notify_node_leave(vap
->iv_bss
);
302 ts
->tdma_peer
= NULL
;
304 * Treat beacon miss like an associate failure wrt the
305 * scan policy; this forces the entry in the scan cache
306 * to be ignored after several tries.
308 ieee80211_scan_assoc_fail(vap
, vap
->iv_bss
->ni_macaddr
,
309 IEEE80211_STATUS_TIMEOUT
);
312 ts
->tdma_inuse
= 0; /* clear slot usage */
314 ieee80211_new_state(vap
, IEEE80211_S_SCAN
, 0);
318 tdma_recv_mgmt(struct ieee80211_node
*ni
, struct mbuf
*m0
,
319 int subtype
, int rssi
, int nf
)
321 struct ieee80211com
*ic
= ni
->ni_ic
;
322 struct ieee80211vap
*vap
= ni
->ni_vap
;
323 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
325 if (subtype
== IEEE80211_FC0_SUBTYPE_BEACON
&&
326 (ic
->ic_flags
& IEEE80211_F_SCAN
) == 0) {
327 struct ieee80211_frame
*wh
= mtod(m0
, struct ieee80211_frame
*);
328 struct ieee80211_scanparams scan
;
330 if (ieee80211_parse_beacon(ni
, m0
, &scan
) != 0)
332 if (scan
.tdma
== NULL
) {
334 * TDMA stations must beacon a TDMA ie; ignore
336 * XXX detect overlapping bss and change channel
338 IEEE80211_DISCARD(vap
,
339 IEEE80211_MSG_ELEMID
| IEEE80211_MSG_INPUT
,
340 wh
, ieee80211_mgt_subtype_name
[subtype
>>
341 IEEE80211_FC0_SUBTYPE_SHIFT
],
343 vap
->iv_stats
.is_rx_mgtdiscard
++;
346 if (ni
== vap
->iv_bss
&&
347 !IEEE80211_ADDR_EQ(wh
->i_addr2
, ni
->ni_macaddr
)) {
349 * Fake up a node for this newly
350 * discovered member of the IBSS.
352 ni
= ieee80211_add_neighbor(vap
, wh
, &scan
);
354 /* NB: stat kept for alloc failure */
359 * Check for state updates.
361 if (IEEE80211_ADDR_EQ(wh
->i_addr3
, ni
->ni_bssid
)) {
363 * Count frame now that we know it's to be processed.
365 vap
->iv_stats
.is_rx_beacon
++;
366 IEEE80211_NODE_STAT(ni
, rx_beacons
);
368 * Record tsf of last beacon. NB: this must be
369 * done before calling tdma_process_params
370 * as deeper routines reference it.
372 memcpy(&ni
->ni_tstamp
.data
, scan
.tstamp
,
373 sizeof(ni
->ni_tstamp
.data
));
375 * Count beacon frame for s/w bmiss handling.
377 vap
->iv_swbmiss_count
++;
379 * Process tdma ie. The contents are used to sync
380 * the slot timing, reconfigure the bss, etc.
382 (void) tdma_process_params(ni
, scan
.tdma
, rssi
, nf
, wh
);
386 * NB: defer remaining work to the adhoc code; this causes
387 * 2x parsing of the frame but should happen infrequently
390 ts
->tdma_recv_mgmt(ni
, m0
, subtype
, rssi
, nf
);
394 * Update TDMA state on receipt of a beacon frame with
395 * a TDMA information element. The sender's identity
396 * is provided so we can track who our peer is. If pickslot
397 * is non-zero we scan the slot allocation state in the ie
398 * to locate a free slot for our use.
401 tdma_update(struct ieee80211vap
*vap
, const struct ieee80211_tdma_param
*tdma
,
402 struct ieee80211_node
*ni
, int pickslot
)
404 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
405 int slot
, slotlen
, update
;
407 KASSERT(vap
->iv_caps
& IEEE80211_C_TDMA
,
408 ("not a tdma vap, caps 0x%x", vap
->iv_caps
));
411 if (tdma
->tdma_slotcnt
!= ts
->tdma_slotcnt
) {
412 if (!TDMA_SLOTCNT_VALID(tdma
->tdma_slotcnt
)) {
413 if (ppsratecheck(&ts
->tdma_lastprint
, &ts
->tdma_fails
, 1))
414 printf("%s: bad slot cnt %u\n",
415 __func__
, tdma
->tdma_slotcnt
);
418 update
|= TDMA_UPDATE_SLOTCNT
;
420 slotlen
= le16toh(tdma
->tdma_slotlen
) * 100;
421 if (slotlen
!= ts
->tdma_slotlen
) {
422 if (!TDMA_SLOTLEN_VALID(slotlen
)) {
423 if (ppsratecheck(&ts
->tdma_lastprint
, &ts
->tdma_fails
, 1))
424 printf("%s: bad slot len %u\n",
428 update
|= TDMA_UPDATE_SLOTLEN
;
430 if (tdma
->tdma_bintval
!= ts
->tdma_bintval
) {
431 if (!TDMA_BINTVAL_VALID(tdma
->tdma_bintval
)) {
432 if (ppsratecheck(&ts
->tdma_lastprint
, &ts
->tdma_fails
, 1))
433 printf("%s: bad beacon interval %u\n",
434 __func__
, tdma
->tdma_bintval
);
437 update
|= TDMA_UPDATE_BINTVAL
;
439 slot
= ts
->tdma_slot
;
442 * Pick unoccupied slot. Note we never choose slot 0.
444 for (slot
= tdma
->tdma_slotcnt
-1; slot
> 0; slot
--)
445 if (isclr(tdma
->tdma_inuse
, slot
))
448 printf("%s: no free slot, slotcnt %u inuse: 0x%x\n",
449 __func__
, tdma
->tdma_slotcnt
,
450 tdma
->tdma_inuse
[0]);
451 /* XXX need to do something better */
454 if (slot
!= ts
->tdma_slot
)
455 update
|= TDMA_UPDATE_SLOT
;
457 if (ni
!= ts
->tdma_peer
) {
458 /* update everything */
459 update
= TDMA_UPDATE_SLOT
460 | TDMA_UPDATE_SLOTCNT
461 | TDMA_UPDATE_SLOTLEN
462 | TDMA_UPDATE_BINTVAL
;
467 * New/changed parameters; update runtime state.
469 /* XXX overwrites user parameters */
470 if (update
& TDMA_UPDATE_SLOTCNT
)
471 ts
->tdma_slotcnt
= tdma
->tdma_slotcnt
;
472 if (update
& TDMA_UPDATE_SLOTLEN
)
473 ts
->tdma_slotlen
= slotlen
;
474 if (update
& TDMA_UPDATE_SLOT
)
475 ts
->tdma_slot
= slot
;
476 if (update
& TDMA_UPDATE_BINTVAL
)
477 ts
->tdma_bintval
= tdma
->tdma_bintval
;
478 /* mark beacon to be updated before next xmit */
479 ieee80211_beacon_notify(vap
, IEEE80211_BEACON_TDMA
);
481 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_TDMA
,
482 "%s: slot %u slotcnt %u slotlen %u us bintval %u\n",
483 __func__
, ts
->tdma_slot
, ts
->tdma_slotcnt
,
484 ts
->tdma_slotlen
, ts
->tdma_bintval
);
487 * Notify driver. Note we can be called before
488 * entering RUN state if we scanned and are
489 * joining an existing bss. In that case do not
490 * call the driver because not all necessary state
491 * has been setup. The next beacon will dtrt.
493 if (vap
->iv_state
== IEEE80211_S_RUN
)
494 vap
->iv_ic
->ic_tdma_update(ni
, tdma
, update
);
496 * Dispatch join event on first beacon from new master.
498 if (ts
->tdma_peer
!= ni
) {
499 if (ts
->tdma_peer
!= NULL
)
500 ieee80211_notify_node_leave(vap
->iv_bss
);
501 ieee80211_notify_node_join(ni
, 1);
502 /* NB: no reference, we just use the address */
509 * Process received TDMA parameters.
512 tdma_process_params(struct ieee80211_node
*ni
, const u_int8_t
*ie
,
513 int rssi
, int nf
, const struct ieee80211_frame
*wh
)
515 struct ieee80211vap
*vap
= ni
->ni_vap
;
516 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
517 const struct ieee80211_tdma_param
*tdma
=
518 (const struct ieee80211_tdma_param
*) ie
;
521 KASSERT(vap
->iv_caps
& IEEE80211_C_TDMA
,
522 ("not a tdma vap, caps 0x%x", vap
->iv_caps
));
524 if (len
< sizeof(*tdma
) - 2) {
525 IEEE80211_DISCARD_IE(vap
,
526 IEEE80211_MSG_ELEMID
| IEEE80211_MSG_TDMA
,
527 wh
, "tdma", "too short, len %u", len
);
528 return IEEE80211_REASON_IE_INVALID
;
530 if (tdma
->tdma_version
!= ts
->tdma_version
) {
531 IEEE80211_DISCARD_IE(vap
,
532 IEEE80211_MSG_ELEMID
| IEEE80211_MSG_TDMA
,
533 wh
, "tdma", "bad version %u (ours %u)",
534 tdma
->tdma_version
, ts
->tdma_version
);
535 return IEEE80211_REASON_IE_INVALID
;
538 * NB: ideally we'd check against tdma_slotcnt, but that
539 * would require extra effort so do this easy check that
540 * covers the work below; more stringent checks are done
541 * before we make more extensive use of the ie contents.
543 if (tdma
->tdma_slot
>= TDMA_MAXSLOTS
) {
544 IEEE80211_DISCARD_IE(vap
,
545 IEEE80211_MSG_ELEMID
| IEEE80211_MSG_TDMA
,
546 wh
, "tdma", "invalid slot %u", tdma
->tdma_slot
);
547 return IEEE80211_REASON_IE_INVALID
;
550 * Can reach here while scanning, update
551 * operational state only in RUN state.
553 if (vap
->iv_state
== IEEE80211_S_RUN
) {
554 if (tdma
->tdma_slot
!= ts
->tdma_slot
&&
555 isclr(ts
->tdma_inuse
, tdma
->tdma_slot
)) {
556 IEEE80211_NOTE(vap
, IEEE80211_MSG_TDMA
, ni
,
557 "discovered in slot %u", tdma
->tdma_slot
);
558 setbit(ts
->tdma_inuse
, tdma
->tdma_slot
);
559 /* XXX dispatch event only when operating as master */
560 if (ts
->tdma_slot
== 0)
561 ieee80211_notify_node_join(ni
, 1);
563 setbit(ts
->tdma_active
, tdma
->tdma_slot
);
564 if (tdma
->tdma_slot
== ts
->tdma_slot
-1) {
566 * Slave tsf synchronization to station
567 * just before us in the schedule. The driver
568 * is responsible for copying the timestamp
569 * of the received beacon into our beacon
570 * frame so the sender can calculate round
571 * trip time. We cannot do that here because
572 * we don't know how to update our beacon frame.
574 (void) tdma_update(vap
, tdma
, ni
, 0);
575 /* XXX reschedule swbmiss timer on parameter change */
576 } else if (tdma
->tdma_slot
== ts
->tdma_slot
+1) {
579 uint32_t rstamp
= (uint32_t) le64toh(rs
->tsf
);
583 * Use returned timstamp to calculate the
586 memcpy(&tstamp
, tdma
->tdma_tstamp
, 8);
588 /* XXX use only 15 bits of rstamp */
589 rtt
= rstamp
- (le64toh(tstamp
) & 0x7fff);
592 /* XXX hack to quiet normal use */
593 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_DOT1X
,
594 "tdma rtt %5u [rstamp %5u tstamp %llu]\n",
596 (unsigned long long) le64toh(tstamp
));
598 } else if (tdma
->tdma_slot
== ts
->tdma_slot
&&
599 le64toh(ni
->ni_tstamp
.tsf
) > vap
->iv_bss
->ni_tstamp
.tsf
) {
601 * Station using the same slot as us and has
602 * been around longer than us; we must move.
603 * Note this can happen if stations do not
604 * see each other while scanning.
606 IEEE80211_DPRINTF(vap
, IEEE80211_MSG_TDMA
,
607 "slot %u collision rxtsf %llu tsf %llu\n",
609 (unsigned long long) le64toh(ni
->ni_tstamp
.tsf
),
610 vap
->iv_bss
->ni_tstamp
.tsf
);
611 setbit(ts
->tdma_inuse
, tdma
->tdma_slot
);
613 (void) tdma_update(vap
, tdma
, ni
, 1);
620 ieee80211_tdma_getslot(struct ieee80211vap
*vap
)
622 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
624 KASSERT(vap
->iv_caps
& IEEE80211_C_TDMA
,
625 ("not a tdma vap, caps 0x%x", vap
->iv_caps
));
626 return ts
->tdma_slot
;
630 * Parse a TDMA ie on station join and use it to setup node state.
633 ieee80211_parse_tdma(struct ieee80211_node
*ni
, const uint8_t *ie
)
635 struct ieee80211vap
*vap
= ni
->ni_vap
;
637 if (vap
->iv_caps
& IEEE80211_C_TDMA
) {
638 const struct ieee80211_tdma_param
*tdma
=
639 (const struct ieee80211_tdma_param
*)ie
;
640 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
642 * Adopt TDMA configuration when joining an
645 setbit(ts
->tdma_inuse
, tdma
->tdma_slot
);
646 (void) tdma_update(vap
, tdma
, ni
, 1);
648 * Propagate capabilities based on the local
649 * configuration and the remote station's advertised
650 * capabilities. In particular this permits us to
651 * enable use of QoS to disable ACK's.
653 if ((vap
->iv_flags
& IEEE80211_F_WME
) &&
654 ni
->ni_ies
.wme_ie
!= NULL
)
655 ni
->ni_flags
|= IEEE80211_NODE_QOS
;
659 #define TDMA_OUI_BYTES 0x00, 0x03, 0x7f
661 * Add a TDMA parameters element to a frame.
664 ieee80211_add_tdma(uint8_t *frm
, struct ieee80211vap
*vap
)
666 #define ADDSHORT(frm, v) do { \
667 frm[0] = (v) & 0xff; \
671 static const struct ieee80211_tdma_param param
= {
672 .tdma_id
= IEEE80211_ELEMID_VENDOR
,
673 .tdma_len
= sizeof(struct ieee80211_tdma_param
) - 2,
674 .tdma_oui
= { TDMA_OUI_BYTES
},
675 .tdma_type
= TDMA_OUI_TYPE
,
676 .tdma_subtype
= TDMA_SUBTYPE_PARAM
,
677 .tdma_version
= TDMA_VERSION
,
679 const struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
682 KASSERT(vap
->iv_caps
& IEEE80211_C_TDMA
,
683 ("not a tdma vap, caps 0x%x", vap
->iv_caps
));
685 memcpy(frm
, ¶m
, sizeof(param
));
686 frm
+= __offsetof(struct ieee80211_tdma_param
, tdma_slot
);
687 *frm
++ = ts
->tdma_slot
;
688 *frm
++ = ts
->tdma_slotcnt
;
689 /* NB: convert units to fit in 16-bits */
690 slotlen
= ts
->tdma_slotlen
/ 100; /* 100us units */
691 ADDSHORT(frm
, slotlen
);
692 *frm
++ = ts
->tdma_bintval
;
693 *frm
++ = ts
->tdma_inuse
[0];
694 frm
+= 10; /* pad+timestamp */
698 #undef TDMA_OUI_BYTES
701 * Update TDMA state at TBTT.
704 ieee80211_tdma_update_beacon(struct ieee80211vap
*vap
,
705 struct ieee80211_beacon_offsets
*bo
)
707 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
709 KASSERT(vap
->iv_caps
& IEEE80211_C_TDMA
,
710 ("not a tdma vap, caps 0x%x", vap
->iv_caps
));
712 if (isset(bo
->bo_flags
, IEEE80211_BEACON_TDMA
)) {
713 (void) ieee80211_add_tdma(bo
->bo_tdma
, vap
);
714 clrbit(bo
->bo_flags
, IEEE80211_BEACON_TDMA
);
716 if (ts
->tdma_slot
!= 0) /* only on master */
718 if (ts
->tdma_count
<= 0) {
720 * Time to update the mask of active/inuse stations.
721 * We track stations that we've received a beacon
722 * frame from and update this mask periodically.
723 * This allows us to miss a few beacons before marking
724 * a slot free for re-use.
726 ts
->tdma_inuse
[0] = ts
->tdma_active
[0];
727 ts
->tdma_active
[0] = 0x01;
728 /* update next time 'round */
729 /* XXX use notify framework */
730 setbit(bo
->bo_flags
, IEEE80211_BEACON_TDMA
);
731 /* NB: use s/w beacon miss threshold; may be too high */
732 ts
->tdma_count
= vap
->iv_bmissthreshold
-1;
738 tdma_ioctl_get80211(struct ieee80211vap
*vap
, struct ieee80211req
*ireq
)
740 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
742 if ((vap
->iv_caps
& IEEE80211_C_TDMA
) == 0)
745 switch (ireq
->i_type
) {
746 case IEEE80211_IOC_TDMA_SLOT
:
747 ireq
->i_val
= ts
->tdma_slot
;
749 case IEEE80211_IOC_TDMA_SLOTCNT
:
750 ireq
->i_val
= ts
->tdma_slotcnt
;
752 case IEEE80211_IOC_TDMA_SLOTLEN
:
753 ireq
->i_val
= ts
->tdma_slotlen
;
755 case IEEE80211_IOC_TDMA_BINTERVAL
:
756 ireq
->i_val
= ts
->tdma_bintval
;
763 IEEE80211_IOCTL_GET(tdma
, tdma_ioctl_get80211
);
766 tdma_ioctl_set80211(struct ieee80211vap
*vap
, struct ieee80211req
*ireq
)
768 struct ieee80211_tdma_state
*ts
= vap
->iv_tdma
;
770 if ((vap
->iv_caps
& IEEE80211_C_TDMA
) == 0)
773 switch (ireq
->i_type
) {
774 case IEEE80211_IOC_TDMA_SLOT
:
775 if (!(0 <= ireq
->i_val
&& ireq
->i_val
<= ts
->tdma_slotcnt
))
777 if (ireq
->i_val
!= ts
->tdma_slot
) {
778 ts
->tdma_slot
= ireq
->i_val
;
782 case IEEE80211_IOC_TDMA_SLOTCNT
:
783 if (!TDMA_SLOTCNT_VALID(ireq
->i_val
))
785 if (ireq
->i_val
!= ts
->tdma_slotcnt
) {
786 ts
->tdma_slotcnt
= ireq
->i_val
;
790 case IEEE80211_IOC_TDMA_SLOTLEN
:
793 * 150 insures at least 1/8 TU
794 * 0xfffff is the max duration for bursting
795 * (implict by way of 16-bit data type for i_val)
797 if (!TDMA_SLOTLEN_VALID(ireq
->i_val
))
799 if (ireq
->i_val
!= ts
->tdma_slotlen
) {
800 ts
->tdma_slotlen
= ireq
->i_val
;
804 case IEEE80211_IOC_TDMA_BINTERVAL
:
805 if (!TDMA_BINTVAL_VALID(ireq
->i_val
))
807 if (ireq
->i_val
!= ts
->tdma_bintval
) {
808 ts
->tdma_bintval
= ireq
->i_val
;
817 ieee80211_beacon_notify(vap
, IEEE80211_BEACON_TDMA
);
820 IEEE80211_IOCTL_SET(tdma
, tdma_ioctl_set80211
);