ieee80211_tdma.c revision 191016
1/*- 2 * Copyright (c) 2007-2009 Sam Leffler, Errno Consulting 3 * Copyright (c) 2007-2009 Intel Corporation 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 * 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. 25 */ 26 27#include <sys/cdefs.h> 28#ifdef __FreeBSD__ 29__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_tdma.c 191016 2009-04-13 20:50:07Z sam $"); 30#endif 31 32/* 33 * IEEE 802.11 TDMA mode support. 34 */ 35#include "opt_inet.h" 36#include "opt_tdma.h" 37#include "opt_wlan.h" 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/mbuf.h> 42#include <sys/malloc.h> 43#include <sys/kernel.h> 44 45#include <sys/socket.h> 46#include <sys/sockio.h> 47#include <sys/endian.h> 48#include <sys/errno.h> 49#include <sys/proc.h> 50#include <sys/sysctl.h> 51 52#include <net/if.h> 53#include <net/if_media.h> 54#include <net/if_llc.h> 55#include <net/ethernet.h> 56 57#include <net/bpf.h> 58 59#include <net80211/ieee80211_var.h> 60#include <net80211/ieee80211_tdma.h> 61#include <net80211/ieee80211_input.h> 62 63#ifndef TDMA_SLOTLEN_DEFAULT 64#define TDMA_SLOTLEN_DEFAULT 10*1000 /* 10ms */ 65#endif 66#ifndef TDMA_SLOTCNT_DEFAULT 67#define TDMA_SLOTCNT_DEFAULT 2 /* 2x (pt-to-pt) */ 68#endif 69#ifndef TDMA_BINTVAL_DEFAULT 70#define TDMA_BINTVAL_DEFAULT 5 /* 5x ~= 100TU beacon intvl */ 71#endif 72#ifndef TDMA_TXRATE_11B_DEFAULT 73#define TDMA_TXRATE_11B_DEFAULT 2*11 74#endif 75#ifndef TDMA_TXRATE_11G_DEFAULT 76#define TDMA_TXRATE_11G_DEFAULT 2*24 77#endif 78#ifndef TDMA_TXRATE_11A_DEFAULT 79#define TDMA_TXRATE_11A_DEFAULT 2*24 80#endif 81#ifndef TDMA_TXRATE_STURBO_A_DEFAULT 82#define TDMA_TXRATE_STURBO_A_DEFAULT 2*24 83#endif 84#ifndef TDMA_TXRATE_HALF_DEFAULT 85#define TDMA_TXRATE_HALF_DEFAULT 2*12 86#endif 87#ifndef TDMA_TXRATE_QUARTER_DEFAULT 88#define TDMA_TXRATE_QUARTER_DEFAULT 2*6 89#endif 90#ifndef TDMA_TXRATE_11NA_DEFAULT 91#define TDMA_TXRATE_11NA_DEFAULT (4 | IEEE80211_RATE_MCS) 92#endif 93#ifndef TDMA_TXRATE_11NG_DEFAULT 94#define TDMA_TXRATE_11NG_DEFAULT (4 | IEEE80211_RATE_MCS) 95#endif 96 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)) 106 107static void tdma_vdetach(struct ieee80211vap *vap); 108static int tdma_newstate(struct ieee80211vap *, enum ieee80211_state, int); 109static void tdma_beacon_miss(struct ieee80211vap *vap); 110static void tdma_recv_mgmt(struct ieee80211_node *, struct mbuf *, 111 int subtype, int rssi, int noise, uint32_t rstamp); 112static int tdma_update(struct ieee80211vap *vap, 113 const struct ieee80211_tdma_param *tdma, struct ieee80211_node *ni, 114 int pickslot); 115static int tdma_process_params(struct ieee80211_node *ni, 116 const u_int8_t *ie, u_int32_t rstamp, const struct ieee80211_frame *wh); 117 118static void 119settxparms(struct ieee80211vap *vap, enum ieee80211_phymode mode, int rate) 120{ 121 vap->iv_txparms[mode].ucastrate = rate; 122 vap->iv_txparms[mode].mcastrate = rate; 123} 124 125static void 126setackpolicy(struct ieee80211com *ic, int noack) 127{ 128 struct ieee80211_wme_state *wme = &ic->ic_wme; 129 int ac; 130 131 for (ac = 0; ac < WME_NUM_AC; ac++) { 132 wme->wme_chanParams.cap_wmeParams[ac].wmep_noackPolicy = noack; 133 wme->wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy = noack; 134 } 135} 136 137void 138ieee80211_tdma_vattach(struct ieee80211vap *vap) 139{ 140 struct ieee80211_tdma_state *ts; 141 142 KASSERT(vap->iv_caps & IEEE80211_C_TDMA, 143 ("not a tdma vap, caps 0x%x", vap->iv_caps)); 144 145 ts = (struct ieee80211_tdma_state *) malloc( 146 sizeof(struct ieee80211_tdma_state), M_80211_VAP, M_NOWAIT | M_ZERO); 147 if (ts == NULL) { 148 printf("%s: cannot allocate TDMA state block\n", __func__); 149 /* NB: fall back to adhdemo mode */ 150 vap->iv_caps &= ~IEEE80211_C_TDMA; 151 return; 152 } 153 /* NB: default configuration is passive so no beacons */ 154 ts->tdma_version = TDMA_VERSION; 155 ts->tdma_slotlen = TDMA_SLOTLEN_DEFAULT; 156 ts->tdma_slotcnt = TDMA_SLOTCNT_DEFAULT; 157 ts->tdma_bintval = TDMA_BINTVAL_DEFAULT; 158 ts->tdma_slot = 1; /* passive operation */ 159 160 /* setup default fixed rates */ 161 settxparms(vap, IEEE80211_MODE_11A, TDMA_TXRATE_11A_DEFAULT); 162 settxparms(vap, IEEE80211_MODE_11B, TDMA_TXRATE_11B_DEFAULT); 163 settxparms(vap, IEEE80211_MODE_11G, TDMA_TXRATE_11G_DEFAULT); 164 settxparms(vap, IEEE80211_MODE_STURBO_A, TDMA_TXRATE_STURBO_A_DEFAULT); 165 settxparms(vap, IEEE80211_MODE_11NA, TDMA_TXRATE_11NA_DEFAULT); 166 settxparms(vap, IEEE80211_MODE_11NG, TDMA_TXRATE_11NG_DEFAULT); 167 settxparms(vap, IEEE80211_MODE_HALF, TDMA_TXRATE_HALF_DEFAULT); 168 settxparms(vap, IEEE80211_MODE_QUARTER, TDMA_TXRATE_QUARTER_DEFAULT); 169 170 setackpolicy(vap->iv_ic, 1); /* disable ACK's */ 171 172 ts->tdma_opdetach = vap->iv_opdetach; 173 vap->iv_opdetach = tdma_vdetach; 174 ts->tdma_newstate = vap->iv_newstate; 175 vap->iv_newstate = tdma_newstate; 176 vap->iv_bmiss = tdma_beacon_miss; 177 ts->tdma_recv_mgmt = vap->iv_recv_mgmt; 178 vap->iv_recv_mgmt = tdma_recv_mgmt; 179 180 vap->iv_tdma = ts; 181} 182 183static void 184tdma_vdetach(struct ieee80211vap *vap) 185{ 186 struct ieee80211_tdma_state *ts = vap->iv_tdma; 187 188 ts->tdma_opdetach(vap); 189 free(vap->iv_tdma, M_80211_VAP); 190 191 setackpolicy(vap->iv_ic, 0); /* enable ACK's */ 192} 193 194static void 195sta_leave(void *arg, struct ieee80211_node *ni) 196{ 197 struct ieee80211vap *vap = arg; 198 199 if (ni->ni_vap == vap && ni != vap->iv_bss) 200 ieee80211_node_leave(ni); 201} 202 203/* 204 * TDMA state machine handler. 205 */ 206static int 207tdma_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 208{ 209 struct ieee80211_tdma_state *ts = vap->iv_tdma; 210 struct ieee80211com *ic = vap->iv_ic; 211 enum ieee80211_state ostate; 212 int status; 213 214 IEEE80211_LOCK_ASSERT(ic); 215 216 ostate = vap->iv_state; 217 IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n", 218 __func__, ieee80211_state_name[ostate], 219 ieee80211_state_name[nstate], arg); 220 221 if (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS) 222 callout_stop(&vap->iv_swbmiss); 223 if (nstate == IEEE80211_S_SCAN && 224 (ostate == IEEE80211_S_INIT || ostate == IEEE80211_S_RUN) && 225 ts->tdma_slot != 0) { 226 /* 227 * Override adhoc behaviour when operating as a slave; 228 * we need to scan even if the channel is locked. 229 */ 230 vap->iv_state = nstate; /* state transition */ 231 ieee80211_cancel_scan(vap); /* background scan */ 232 if (ostate == IEEE80211_S_RUN) { 233 /* purge station table; entries are stale */ 234 ieee80211_iterate_nodes(&ic->ic_sta, sta_leave, vap); 235 } 236 if (vap->iv_flags_ext & IEEE80211_FEXT_SCANREQ) { 237 ieee80211_check_scan(vap, 238 vap->iv_scanreq_flags, 239 vap->iv_scanreq_duration, 240 vap->iv_scanreq_mindwell, 241 vap->iv_scanreq_maxdwell, 242 vap->iv_scanreq_nssid, vap->iv_scanreq_ssid); 243 vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ; 244 } else 245 ieee80211_check_scan_current(vap); 246 status = 0; 247 } else { 248 status = ts->tdma_newstate(vap, nstate, arg); 249 } 250 if (status == 0 && 251 nstate == IEEE80211_S_RUN && ostate != IEEE80211_S_RUN && 252 (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS) && 253 ts->tdma_slot != 0 && 254 vap->iv_des_chan == IEEE80211_CHAN_ANYC) { 255 /* 256 * Start s/w beacon miss timer for slave devices w/o 257 * hardware support. Note we do this only if we're 258 * not locked to a channel (i.e. roam to follow the 259 * master). The 2x is a fudge for our doing this in 260 * software. 261 */ 262 vap->iv_swbmiss_period = IEEE80211_TU_TO_TICKS( 263 2 * vap->iv_bmissthreshold * ts->tdma_bintval * 264 ((ts->tdma_slotcnt * ts->tdma_slotlen) / 1024)); 265 vap->iv_swbmiss_count = 0; 266 callout_reset(&vap->iv_swbmiss, vap->iv_swbmiss_period, 267 ieee80211_swbmiss, vap); 268 } 269 return status; 270} 271 272static void 273tdma_beacon_miss(struct ieee80211vap *vap) 274{ 275 struct ieee80211_tdma_state *ts = vap->iv_tdma; 276 277 KASSERT((vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0, ("scanning")); 278 KASSERT(vap->iv_state == IEEE80211_S_RUN, 279 ("wrong state %d", vap->iv_state)); 280 281 IEEE80211_DPRINTF(vap, 282 IEEE80211_MSG_STATE | IEEE80211_MSG_TDMA | IEEE80211_MSG_DEBUG, 283 "beacon miss, mode %u state %s\n", 284 vap->iv_opmode, ieee80211_state_name[vap->iv_state]); 285 286 if (ts->tdma_peer != NULL) { /* XXX? can this be null? */ 287 ieee80211_notify_node_leave(vap->iv_bss); 288 ts->tdma_peer = NULL; 289 /* 290 * Treat beacon miss like an associate failure wrt the 291 * scan policy; this forces the entry in the scan cache 292 * to be ignored after several tries. 293 */ 294 ieee80211_scan_assoc_fail(vap, vap->iv_bss->ni_macaddr, 295 IEEE80211_STATUS_TIMEOUT); 296 } 297#if 0 298 ts->tdma_inuse = 0; /* clear slot usage */ 299#endif 300 ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); 301} 302 303static void 304tdma_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, 305 int subtype, int rssi, int noise, uint32_t rstamp) 306{ 307 struct ieee80211com *ic = ni->ni_ic; 308 struct ieee80211vap *vap = ni->ni_vap; 309 struct ieee80211_tdma_state *ts = vap->iv_tdma; 310 311 if (subtype == IEEE80211_FC0_SUBTYPE_BEACON && 312 (ic->ic_flags & IEEE80211_F_SCAN) == 0) { 313 struct ieee80211_frame *wh = mtod(m0, struct ieee80211_frame *); 314 struct ieee80211_scanparams scan; 315 316 if (ieee80211_parse_beacon(ni, m0, &scan) != 0) 317 return; 318 if (scan.tdma == NULL) { 319 /* 320 * TDMA stations must beacon a TDMA ie; ignore 321 * any other station. 322 * XXX detect overlapping bss and change channel 323 */ 324 IEEE80211_DISCARD(vap, 325 IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT, 326 wh, ieee80211_mgt_subtype_name[subtype >> 327 IEEE80211_FC0_SUBTYPE_SHIFT], 328 "%s", "no TDMA ie"); 329 vap->iv_stats.is_rx_mgtdiscard++; 330 return; 331 } 332 if (ni == vap->iv_bss && 333 !IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) { 334 /* 335 * Fake up a node for this newly 336 * discovered member of the IBSS. 337 */ 338 ni = ieee80211_add_neighbor(vap, wh, &scan); 339 if (ni == NULL) { 340 /* NB: stat kept for alloc failure */ 341 return; 342 } 343 } 344 /* 345 * Check for state updates. 346 */ 347 if (IEEE80211_ADDR_EQ(wh->i_addr3, ni->ni_bssid)) { 348 /* 349 * Count frame now that we know it's to be processed. 350 */ 351 vap->iv_stats.is_rx_beacon++; 352 IEEE80211_NODE_STAT(ni, rx_beacons); 353 /* 354 * Record tsf of last beacon. NB: this must be 355 * done before calling tdma_process_params 356 * as deeper routines reference it. 357 */ 358 memcpy(&ni->ni_tstamp.data, scan.tstamp, 359 sizeof(ni->ni_tstamp.data)); 360 /* 361 * Count beacon frame for s/w bmiss handling. 362 */ 363 vap->iv_swbmiss_count++; 364 /* 365 * Process tdma ie. The contents are used to sync 366 * the slot timing, reconfigure the bss, etc. 367 */ 368 (void) tdma_process_params(ni, scan.tdma, rstamp, wh); 369 return; 370 } 371 /* 372 * NB: defer remaining work to the adhoc code; this causes 373 * 2x parsing of the frame but should happen infrequently 374 */ 375 } 376 ts->tdma_recv_mgmt(ni, m0, subtype, rssi, noise, rstamp); 377} 378 379/* 380 * Update TDMA state on receipt of a beacon frame with 381 * a TDMA information element. The sender's identity 382 * is provided so we can track who our peer is. If pickslot 383 * is non-zero we scan the slot allocation state in the ie 384 * to locate a free slot for our use. 385 */ 386static int 387tdma_update(struct ieee80211vap *vap, const struct ieee80211_tdma_param *tdma, 388 struct ieee80211_node *ni, int pickslot) 389{ 390 struct ieee80211_tdma_state *ts = vap->iv_tdma; 391 int slot, slotlen, update; 392 393 KASSERT(vap->iv_caps & IEEE80211_C_TDMA, 394 ("not a tdma vap, caps 0x%x", vap->iv_caps)); 395 396 update = 0; 397 if (tdma->tdma_slotcnt != ts->tdma_slotcnt) { 398 if (!TDMA_SLOTCNT_VALID(tdma->tdma_slotcnt)) { 399 if (ppsratecheck(&ts->tdma_lastprint, &ts->tdma_fails, 1)) 400 printf("%s: bad slot cnt %u\n", 401 __func__, tdma->tdma_slotcnt); 402 return 0; 403 } 404 update |= TDMA_UPDATE_SLOTCNT; 405 } 406 slotlen = le16toh(tdma->tdma_slotlen) * 100; 407 if (slotlen != ts->tdma_slotlen) { 408 if (!TDMA_SLOTLEN_VALID(slotlen)) { 409 if (ppsratecheck(&ts->tdma_lastprint, &ts->tdma_fails, 1)) 410 printf("%s: bad slot len %u\n", 411 __func__, slotlen); 412 return 0; 413 } 414 update |= TDMA_UPDATE_SLOTLEN; 415 } 416 if (tdma->tdma_bintval != ts->tdma_bintval) { 417 if (!TDMA_BINTVAL_VALID(tdma->tdma_bintval)) { 418 if (ppsratecheck(&ts->tdma_lastprint, &ts->tdma_fails, 1)) 419 printf("%s: bad beacon interval %u\n", 420 __func__, tdma->tdma_bintval); 421 return 0; 422 } 423 update |= TDMA_UPDATE_BINTVAL; 424 } 425 slot = ts->tdma_slot; 426 if (pickslot) { 427 /* 428 * Pick unoccupied slot. Note we never choose slot 0. 429 */ 430 for (slot = tdma->tdma_slotcnt-1; slot > 0; slot--) 431 if (isclr(tdma->tdma_inuse, slot)) 432 break; 433 if (slot <= 0) { 434 printf("%s: no free slot, slotcnt %u inuse: 0x%x\n", 435 __func__, tdma->tdma_slotcnt, 436 tdma->tdma_inuse[0]); 437 /* XXX need to do something better */ 438 return 0; 439 } 440 if (slot != ts->tdma_slot) 441 update |= TDMA_UPDATE_SLOT; 442 } 443 if (ni != ts->tdma_peer) { 444 /* update everything */ 445 update = TDMA_UPDATE_SLOT 446 | TDMA_UPDATE_SLOTCNT 447 | TDMA_UPDATE_SLOTLEN 448 | TDMA_UPDATE_BINTVAL; 449 } 450 451 if (update) { 452 /* 453 * New/changed parameters; update runtime state. 454 */ 455 /* XXX overwrites user parameters */ 456 if (update & TDMA_UPDATE_SLOTCNT) 457 ts->tdma_slotcnt = tdma->tdma_slotcnt; 458 if (update & TDMA_UPDATE_SLOTLEN) 459 ts->tdma_slotlen = slotlen; 460 if (update & TDMA_UPDATE_SLOT) 461 ts->tdma_slot = slot; 462 if (update & TDMA_UPDATE_BINTVAL) 463 ts->tdma_bintval = tdma->tdma_bintval; 464 /* mark beacon to be updated before next xmit */ 465 ieee80211_beacon_notify(vap, IEEE80211_BEACON_TDMA); 466 467 IEEE80211_DPRINTF(vap, IEEE80211_MSG_TDMA, 468 "%s: slot %u slotcnt %u slotlen %u us bintval %u\n", 469 __func__, ts->tdma_slot, ts->tdma_slotcnt, 470 100*ts->tdma_slotlen, ts->tdma_bintval); 471 } 472 /* 473 * Notify driver. Note we can be called before 474 * entering RUN state if we scanned and are 475 * joining an existing bss. In that case do not 476 * call the driver because not all necessary state 477 * has been setup. The next beacon will dtrt. 478 */ 479 if (vap->iv_state == IEEE80211_S_RUN) 480 vap->iv_ic->ic_tdma_update(ni, tdma, update); 481 /* 482 * Dispatch join event on first beacon from new master. 483 */ 484 if (ts->tdma_peer != ni) { 485 if (ts->tdma_peer != NULL) 486 ieee80211_notify_node_leave(vap->iv_bss); 487 ieee80211_notify_node_join(ni, 1); 488 /* NB: no reference, we just use the address */ 489 ts->tdma_peer = ni; 490 } 491 return 1; 492} 493 494/* 495 * Process received TDMA parameters. 496 */ 497static int 498tdma_process_params(struct ieee80211_node *ni, 499 const u_int8_t *ie, u_int32_t rstamp, const struct ieee80211_frame *wh) 500{ 501 struct ieee80211vap *vap = ni->ni_vap; 502 struct ieee80211_tdma_state *ts = vap->iv_tdma; 503 const struct ieee80211_tdma_param *tdma = 504 (const struct ieee80211_tdma_param *) ie; 505 u_int len = ie[1]; 506 507 KASSERT(vap->iv_caps & IEEE80211_C_TDMA, 508 ("not a tdma vap, caps 0x%x", vap->iv_caps)); 509 510 if (len < sizeof(*tdma) - 2) { 511 IEEE80211_DISCARD_IE(vap, 512 IEEE80211_MSG_ELEMID | IEEE80211_MSG_TDMA, 513 wh, "tdma", "too short, len %u", len); 514 return IEEE80211_REASON_IE_INVALID; 515 } 516 if (tdma->tdma_version != ts->tdma_version) { 517 IEEE80211_DISCARD_IE(vap, 518 IEEE80211_MSG_ELEMID | IEEE80211_MSG_TDMA, 519 wh, "tdma", "bad version %u (ours %u)", 520 tdma->tdma_version, ts->tdma_version); 521 return IEEE80211_REASON_IE_INVALID; 522 } 523 /* 524 * NB: ideally we'd check against tdma_slotcnt, but that 525 * would require extra effort so do this easy check that 526 * covers the work below; more stringent checks are done 527 * before we make more extensive use of the ie contents. 528 */ 529 if (tdma->tdma_slot >= TDMA_MAXSLOTS) { 530 IEEE80211_DISCARD_IE(vap, 531 IEEE80211_MSG_ELEMID | IEEE80211_MSG_TDMA, 532 wh, "tdma", "invalid slot %u", tdma->tdma_slot); 533 return IEEE80211_REASON_IE_INVALID; 534 } 535 /* 536 * Can reach here while scanning, update 537 * operational state only in RUN state. 538 */ 539 if (vap->iv_state == IEEE80211_S_RUN) { 540 if (tdma->tdma_slot != ts->tdma_slot && 541 isclr(ts->tdma_inuse, tdma->tdma_slot)) { 542 IEEE80211_NOTE(vap, IEEE80211_MSG_TDMA, ni, 543 "discovered in slot %u", tdma->tdma_slot); 544 setbit(ts->tdma_inuse, tdma->tdma_slot); 545 /* XXX dispatch event only when operating as master */ 546 if (ts->tdma_slot == 0) 547 ieee80211_notify_node_join(ni, 1); 548 } 549 setbit(ts->tdma_active, tdma->tdma_slot); 550 if (tdma->tdma_slot == ts->tdma_slot-1) { 551 /* 552 * Slave tsf synchronization to station 553 * just before us in the schedule. The driver 554 * is responsible for copying the timestamp 555 * of the received beacon into our beacon 556 * frame so the sender can calculate round 557 * trip time. We cannot do that here because 558 * we don't know how to update our beacon frame. 559 */ 560 (void) tdma_update(vap, tdma, ni, 0); 561 /* XXX reschedule swbmiss timer on parameter change */ 562 } else if (tdma->tdma_slot == ts->tdma_slot+1) { 563 uint64_t tstamp; 564 int32_t rtt; 565 /* 566 * Use returned timstamp to calculate the 567 * roundtrip time. 568 */ 569 memcpy(&tstamp, tdma->tdma_tstamp, 8); 570 /* XXX use only 15 bits of rstamp */ 571 rtt = rstamp - (le64toh(tstamp) & 0x7fff); 572 if (rtt < 0) 573 rtt += 0x7fff; 574 /* XXX hack to quiet normal use */ 575 IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOT1X, 576 "tdma rtt %5u [rstamp %5u tstamp %llu]\n", 577 rtt, rstamp, 578 (unsigned long long) le64toh(tstamp)); 579 } else if (tdma->tdma_slot == ts->tdma_slot && 580 le64toh(ni->ni_tstamp.tsf) > vap->iv_bss->ni_tstamp.tsf) { 581 /* 582 * Station using the same slot as us and has 583 * been around longer than us; we must move. 584 * Note this can happen if stations do not 585 * see each other while scanning. 586 */ 587 IEEE80211_DPRINTF(vap, IEEE80211_MSG_TDMA, 588 "slot %u collision rxtsf %llu tsf %llu\n", 589 tdma->tdma_slot, 590 (unsigned long long) le64toh(ni->ni_tstamp.tsf), 591 vap->iv_bss->ni_tstamp.tsf); 592 setbit(ts->tdma_inuse, tdma->tdma_slot); 593 594 (void) tdma_update(vap, tdma, ni, 1); 595 } 596 } 597 return 0; 598} 599 600int 601ieee80211_tdma_getslot(struct ieee80211vap *vap) 602{ 603 struct ieee80211_tdma_state *ts = vap->iv_tdma; 604 605 KASSERT(vap->iv_caps & IEEE80211_C_TDMA, 606 ("not a tdma vap, caps 0x%x", vap->iv_caps)); 607 return ts->tdma_slot; 608} 609 610/* 611 * Parse a TDMA ie on station join and use it to setup node state. 612 */ 613void 614ieee80211_parse_tdma(struct ieee80211_node *ni, const uint8_t *ie) 615{ 616 struct ieee80211vap *vap = ni->ni_vap; 617 618 if (vap->iv_caps & IEEE80211_C_TDMA) { 619 const struct ieee80211_tdma_param *tdma = 620 (const struct ieee80211_tdma_param *)ie; 621 struct ieee80211_tdma_state *ts = vap->iv_tdma; 622 /* 623 * Adopt TDMA configuration when joining an 624 * existing network. 625 */ 626 setbit(ts->tdma_inuse, tdma->tdma_slot); 627 (void) tdma_update(vap, tdma, ni, 1); 628 /* 629 * Propagate capabilities based on the local 630 * configuration and the remote station's advertised 631 * capabilities. In particular this permits us to 632 * enable use of QoS to disable ACK's. 633 */ 634 if ((vap->iv_flags & IEEE80211_F_WME) && 635 ni->ni_ies.wme_ie != NULL) 636 ni->ni_flags |= IEEE80211_NODE_QOS; 637 } 638} 639 640#define TDMA_OUI_BYTES 0x00, 0x03, 0x7f 641/* 642 * Add a TDMA parameters element to a frame. 643 */ 644uint8_t * 645ieee80211_add_tdma(uint8_t *frm, struct ieee80211vap *vap) 646{ 647#define ADDSHORT(frm, v) do { \ 648 frm[0] = (v) & 0xff; \ 649 frm[1] = (v) >> 8; \ 650 frm += 2; \ 651} while (0) 652 static const struct ieee80211_tdma_param param = { 653 .tdma_id = IEEE80211_ELEMID_VENDOR, 654 .tdma_len = sizeof(struct ieee80211_tdma_param) - 2, 655 .tdma_oui = { TDMA_OUI_BYTES }, 656 .tdma_type = TDMA_OUI_TYPE, 657 .tdma_subtype = TDMA_SUBTYPE_PARAM, 658 .tdma_version = TDMA_VERSION, 659 }; 660 const struct ieee80211_tdma_state *ts = vap->iv_tdma; 661 uint16_t slotlen; 662 663 KASSERT(vap->iv_caps & IEEE80211_C_TDMA, 664 ("not a tdma vap, caps 0x%x", vap->iv_caps)); 665 666 memcpy(frm, ¶m, sizeof(param)); 667 frm += __offsetof(struct ieee80211_tdma_param, tdma_slot); 668 *frm++ = ts->tdma_slot; 669 *frm++ = ts->tdma_slotcnt; 670 /* NB: convert units to fit in 16-bits */ 671 slotlen = ts->tdma_slotlen / 100; /* 100us units */ 672 ADDSHORT(frm, slotlen); 673 *frm++ = ts->tdma_bintval; 674 *frm++ = ts->tdma_inuse[0]; 675 frm += 10; /* pad+timestamp */ 676 return frm; 677#undef ADDSHORT 678} 679#undef TDMA_OUI_BYTES 680 681/* 682 * Update TDMA state at TBTT. 683 */ 684void 685ieee80211_tdma_update_beacon(struct ieee80211vap *vap, 686 struct ieee80211_beacon_offsets *bo) 687{ 688 struct ieee80211_tdma_state *ts = vap->iv_tdma; 689 690 KASSERT(vap->iv_caps & IEEE80211_C_TDMA, 691 ("not a tdma vap, caps 0x%x", vap->iv_caps)); 692 693 if (isset(bo->bo_flags, IEEE80211_BEACON_TDMA)) { 694 (void) ieee80211_add_tdma(bo->bo_tdma, vap); 695 clrbit(bo->bo_flags, IEEE80211_BEACON_TDMA); 696 } 697 if (ts->tdma_slot != 0) /* only on master */ 698 return; 699 if (ts->tdma_count <= 0) { 700 /* 701 * Time to update the mask of active/inuse stations. 702 * We track stations that we've received a beacon 703 * frame from and update this mask periodically. 704 * This allows us to miss a few beacons before marking 705 * a slot free for re-use. 706 */ 707 ts->tdma_inuse[0] = ts->tdma_active[0]; 708 ts->tdma_active[0] = 0x01; 709 /* update next time 'round */ 710 /* XXX use notify framework */ 711 setbit(bo->bo_flags, IEEE80211_BEACON_TDMA); 712 /* NB: use s/w beacon miss threshold; may be too high */ 713 ts->tdma_count = vap->iv_bmissthreshold-1; 714 } else 715 ts->tdma_count--; 716} 717 718static int 719tdma_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq) 720{ 721 struct ieee80211_tdma_state *ts = vap->iv_tdma; 722 723 if ((vap->iv_caps & IEEE80211_C_TDMA) == 0) 724 return EOPNOTSUPP; 725 726 switch (ireq->i_type) { 727 case IEEE80211_IOC_TDMA_SLOT: 728 ireq->i_val = ts->tdma_slot; 729 break; 730 case IEEE80211_IOC_TDMA_SLOTCNT: 731 ireq->i_val = ts->tdma_slotcnt; 732 break; 733 case IEEE80211_IOC_TDMA_SLOTLEN: 734 ireq->i_val = ts->tdma_slotlen; 735 break; 736 case IEEE80211_IOC_TDMA_BINTERVAL: 737 ireq->i_val = ts->tdma_bintval; 738 break; 739 default: 740 return ENOSYS; 741 } 742 return 0; 743} 744IEEE80211_IOCTL_GET(tdma, tdma_ioctl_get80211); 745 746static int 747tdma_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq) 748{ 749 struct ieee80211_tdma_state *ts = vap->iv_tdma; 750 751 if ((vap->iv_caps & IEEE80211_C_TDMA) == 0) 752 return EOPNOTSUPP; 753 754 switch (ireq->i_type) { 755 case IEEE80211_IOC_TDMA_SLOT: 756 if (!(0 <= ireq->i_val && ireq->i_val <= ts->tdma_slotcnt)) 757 return EINVAL; 758 if (ireq->i_val != ts->tdma_slot) { 759 ts->tdma_slot = ireq->i_val; 760 return ERESTART; 761 } 762 break; 763 case IEEE80211_IOC_TDMA_SLOTCNT: 764 if (!TDMA_SLOTCNT_VALID(ireq->i_val)) 765 return EINVAL; 766 if (ireq->i_val != ts->tdma_slotcnt) { 767 ts->tdma_slotcnt = ireq->i_val; 768 return ERESTART; 769 } 770 break; 771 case IEEE80211_IOC_TDMA_SLOTLEN: 772 /* 773 * XXX 774 * 150 insures at least 1/8 TU 775 * 0xfffff is the max duration for bursting 776 * (implict by way of 16-bit data type for i_val) 777 */ 778 if (!TDMA_SLOTLEN_VALID(ireq->i_val)) 779 return EINVAL; 780 if (ireq->i_val != ts->tdma_slotlen) { 781 ts->tdma_slotlen = ireq->i_val; 782 return ERESTART; 783 } 784 break; 785 case IEEE80211_IOC_TDMA_BINTERVAL: 786 if (!TDMA_BINTVAL_VALID(ireq->i_val)) 787 return EINVAL; 788 if (ireq->i_val != ts->tdma_bintval) { 789 ts->tdma_bintval = ireq->i_val; 790 return ERESTART; 791 } 792 break; 793 default: 794 return ENOSYS; 795 } 796 return 0; 797} 798IEEE80211_IOCTL_SET(tdma, tdma_ioctl_set80211); 799