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