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