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