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 "%s", "no TDMA ie"); 348 vap->iv_stats.is_rx_mgtdiscard++; 349 return; 350 } 351 if (ni == vap->iv_bss && 352 !IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) { 353 /* 354 * Fake up a node for this newly 355 * discovered member of the IBSS. 356 */ 357 ni = ieee80211_add_neighbor(vap, wh, &scan); 358 if (ni == NULL) { 359 /* NB: stat kept for alloc failure */ 360 return; 361 } 362 } 363 /* 364 * Check for state updates. 365 */ 366 if (IEEE80211_ADDR_EQ(wh->i_addr3, ni->ni_bssid)) { 367 /* 368 * Count frame now that we know it's to be processed. 369 */ 370 vap->iv_stats.is_rx_beacon++; 371 IEEE80211_NODE_STAT(ni, rx_beacons); 372 /* 373 * Record tsf of last beacon. NB: this must be 374 * done before calling tdma_process_params 375 * as deeper routines reference it. 376 */ 377 memcpy(&ni->ni_tstamp.data, scan.tstamp, 378 sizeof(ni->ni_tstamp.data)); 379 /* 380 * Count beacon frame for s/w bmiss handling. 381 */ 382 vap->iv_swbmiss_count++; 383 /* 384 * Process tdma ie. The contents are used to sync 385 * the slot timing, reconfigure the bss, etc. 386 */ 387 (void) tdma_process_params(ni, scan.tdma, rssi, nf, wh); 388 return; 389 } 390 /* 391 * NB: defer remaining work to the adhoc code; this causes 392 * 2x parsing of the frame but should happen infrequently 393 */ 394 } 395 ts->tdma_recv_mgmt(ni, m0, subtype, rxs, rssi, nf); 396 } 397 398 /* 399 * Update TDMA state on receipt of a beacon frame with 400 * a TDMA information element. The sender's identity 401 * is provided so we can track who our peer is. If pickslot 402 * is non-zero we scan the slot allocation state in the ie 403 * to locate a free slot for our use. 404 */ 405 static int 406 tdma_update(struct ieee80211vap *vap, const struct ieee80211_tdma_param *tdma, 407 struct ieee80211_node *ni, int pickslot) 408 { 409 struct ieee80211_tdma_state *ts = vap->iv_tdma; 410 int slot, slotlen, update; 411 412 KASSERT(vap->iv_caps & IEEE80211_C_TDMA, 413 ("not a tdma vap, caps 0x%x", vap->iv_caps)); 414 415 update = 0; 416 if (tdma->tdma_slotcnt != ts->tdma_slotcnt) { 417 if (!TDMA_SLOTCNT_VALID(tdma->tdma_slotcnt)) { 418 if (ppsratecheck(&ts->tdma_lastprint, &ts->tdma_fails, 1)) 419 printf("%s: bad slot cnt %u\n", 420 __func__, tdma->tdma_slotcnt); 421 return 0; 422 } 423 update |= TDMA_UPDATE_SLOTCNT; 424 } 425 slotlen = le16toh(tdma->tdma_slotlen) * 100; 426 if (slotlen != ts->tdma_slotlen) { 427 if (!TDMA_SLOTLEN_VALID(slotlen)) { 428 if (ppsratecheck(&ts->tdma_lastprint, &ts->tdma_fails, 1)) 429 printf("%s: bad slot len %u\n", 430 __func__, slotlen); 431 return 0; 432 } 433 update |= TDMA_UPDATE_SLOTLEN; 434 } 435 if (tdma->tdma_bintval != ts->tdma_bintval) { 436 if (!TDMA_BINTVAL_VALID(tdma->tdma_bintval)) { 437 if (ppsratecheck(&ts->tdma_lastprint, &ts->tdma_fails, 1)) 438 printf("%s: bad beacon interval %u\n", 439 __func__, tdma->tdma_bintval); 440 return 0; 441 } 442 update |= TDMA_UPDATE_BINTVAL; 443 } 444 slot = ts->tdma_slot; 445 if (pickslot) { 446 /* 447 * Pick unoccupied slot. Note we never choose slot 0. 448 */ 449 for (slot = tdma->tdma_slotcnt-1; slot > 0; slot--) 450 if (isclr(tdma->tdma_inuse, slot)) 451 break; 452 if (slot <= 0) { 453 printf("%s: no free slot, slotcnt %u inuse: 0x%x\n", 454 __func__, tdma->tdma_slotcnt, 455 tdma->tdma_inuse[0]); 456 /* XXX need to do something better */ 457 return 0; 458 } 459 if (slot != ts->tdma_slot) 460 update |= TDMA_UPDATE_SLOT; 461 } 462 if (ni != ts->tdma_peer) { 463 /* update everything */ 464 update = TDMA_UPDATE_SLOT 465 | TDMA_UPDATE_SLOTCNT 466 | TDMA_UPDATE_SLOTLEN 467 | TDMA_UPDATE_BINTVAL; 468 } 469 470 if (update) { 471 /* 472 * New/changed parameters; update runtime state. 473 */ 474 /* XXX overwrites user parameters */ 475 if (update & TDMA_UPDATE_SLOTCNT) 476 ts->tdma_slotcnt = tdma->tdma_slotcnt; 477 if (update & TDMA_UPDATE_SLOTLEN) 478 ts->tdma_slotlen = slotlen; 479 if (update & TDMA_UPDATE_SLOT) 480 ts->tdma_slot = slot; 481 if (update & TDMA_UPDATE_BINTVAL) 482 ts->tdma_bintval = tdma->tdma_bintval; 483 /* mark beacon to be updated before next xmit */ 484 ieee80211_beacon_notify(vap, IEEE80211_BEACON_TDMA); 485 486 IEEE80211_DPRINTF(vap, IEEE80211_MSG_TDMA, 487 "%s: slot %u slotcnt %u slotlen %u us bintval %u\n", 488 __func__, ts->tdma_slot, ts->tdma_slotcnt, 489 ts->tdma_slotlen, ts->tdma_bintval); 490 } 491 /* 492 * Notify driver. Note we can be called before 493 * entering RUN state if we scanned and are 494 * joining an existing bss. In that case do not 495 * call the driver because not all necessary state 496 * has been setup. The next beacon will dtrt. 497 */ 498 if (vap->iv_state == IEEE80211_S_RUN) 499 vap->iv_ic->ic_tdma_update(ni, tdma, update); 500 /* 501 * Dispatch join event on first beacon from new master. 502 */ 503 if (ts->tdma_peer != ni) { 504 if (ts->tdma_peer != NULL) 505 ieee80211_notify_node_leave(vap->iv_bss); 506 ieee80211_notify_node_join(ni, 1); 507 /* NB: no reference, we just use the address */ 508 ts->tdma_peer = ni; 509 } 510 return 1; 511 } 512 513 /* 514 * Process received TDMA parameters. 515 */ 516 static int 517 tdma_process_params(struct ieee80211_node *ni, const u_int8_t *ie, 518 int rssi, int nf, const struct ieee80211_frame *wh) 519 { 520 struct ieee80211vap *vap = ni->ni_vap; 521 struct ieee80211_tdma_state *ts = vap->iv_tdma; 522 const struct ieee80211_tdma_param *tdma = 523 (const struct ieee80211_tdma_param *) ie; 524 u_int len = ie[1]; 525 526 KASSERT(vap->iv_caps & IEEE80211_C_TDMA, 527 ("not a tdma vap, caps 0x%x", vap->iv_caps)); 528 529 if (len < sizeof(*tdma) - 2) { 530 IEEE80211_DISCARD_IE(vap, 531 IEEE80211_MSG_ELEMID | IEEE80211_MSG_TDMA, 532 wh, "tdma", "too short, len %u", len); 533 return IEEE80211_REASON_IE_INVALID; 534 } 535 if (tdma->tdma_version != ts->tdma_version) { 536 IEEE80211_DISCARD_IE(vap, 537 IEEE80211_MSG_ELEMID | IEEE80211_MSG_TDMA, 538 wh, "tdma", "bad version %u (ours %u)", 539 tdma->tdma_version, ts->tdma_version); 540 return IEEE80211_REASON_IE_INVALID; 541 } 542 /* 543 * NB: ideally we'd check against tdma_slotcnt, but that 544 * would require extra effort so do this easy check that 545 * covers the work below; more stringent checks are done 546 * before we make more extensive use of the ie contents. 547 */ 548 if (tdma->tdma_slot >= TDMA_MAXSLOTS) { 549 IEEE80211_DISCARD_IE(vap, 550 IEEE80211_MSG_ELEMID | IEEE80211_MSG_TDMA, 551 wh, "tdma", "invalid slot %u", tdma->tdma_slot); 552 return IEEE80211_REASON_IE_INVALID; 553 } 554 /* 555 * Can reach here while scanning, update 556 * operational state only in RUN state. 557 */ 558 if (vap->iv_state == IEEE80211_S_RUN) { 559 if (tdma->tdma_slot != ts->tdma_slot && 560 isclr(ts->tdma_inuse, tdma->tdma_slot)) { 561 IEEE80211_NOTE(vap, IEEE80211_MSG_TDMA, ni, 562 "discovered in slot %u", tdma->tdma_slot); 563 setbit(ts->tdma_inuse, tdma->tdma_slot); 564 /* XXX dispatch event only when operating as master */ 565 if (ts->tdma_slot == 0) 566 ieee80211_notify_node_join(ni, 1); 567 } 568 setbit(ts->tdma_active, tdma->tdma_slot); 569 if (tdma->tdma_slot == ts->tdma_slot-1) { 570 /* 571 * Slave tsf synchronization to station 572 * just before us in the schedule. The driver 573 * is responsible for copying the timestamp 574 * of the received beacon into our beacon 575 * frame so the sender can calculate round 576 * trip time. We cannot do that here because 577 * we don't know how to update our beacon frame. 578 */ 579 (void) tdma_update(vap, tdma, ni, 0); 580 /* XXX reschedule swbmiss timer on parameter change */ 581 } else if (tdma->tdma_slot == ts->tdma_slot+1) { 582 uint64_t tstamp; 583 #if 0 584 uint32_t rstamp = (uint32_t) le64toh(rs->tsf); 585 int32_t rtt; 586 #endif 587 /* 588 * Use returned timstamp to calculate the 589 * roundtrip time. 590 */ 591 memcpy(&tstamp, tdma->tdma_tstamp, 8); 592 #if 0 593 /* XXX use only 15 bits of rstamp */ 594 rtt = rstamp - (le64toh(tstamp) & 0x7fff); 595 if (rtt < 0) 596 rtt += 0x7fff; 597 /* XXX hack to quiet normal use */ 598 IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOT1X, 599 "tdma rtt %5u [rstamp %5u tstamp %llu]\n", 600 rtt, rstamp, 601 (unsigned long long) le64toh(tstamp)); 602 #endif 603 } else if (tdma->tdma_slot == ts->tdma_slot && 604 le64toh(ni->ni_tstamp.tsf) > vap->iv_bss->ni_tstamp.tsf) { 605 /* 606 * Station using the same slot as us and has 607 * been around longer than us; we must move. 608 * Note this can happen if stations do not 609 * see each other while scanning. 610 */ 611 IEEE80211_DPRINTF(vap, IEEE80211_MSG_TDMA, 612 "slot %u collision rxtsf %llu tsf %llu\n", 613 tdma->tdma_slot, 614 (unsigned long long) le64toh(ni->ni_tstamp.tsf), 615 vap->iv_bss->ni_tstamp.tsf); 616 setbit(ts->tdma_inuse, tdma->tdma_slot); 617 618 (void) tdma_update(vap, tdma, ni, 1); 619 } 620 } 621 return 0; 622 } 623 624 int 625 ieee80211_tdma_getslot(struct ieee80211vap *vap) 626 { 627 struct ieee80211_tdma_state *ts = vap->iv_tdma; 628 629 KASSERT(vap->iv_caps & IEEE80211_C_TDMA, 630 ("not a tdma vap, caps 0x%x", vap->iv_caps)); 631 return ts->tdma_slot; 632 } 633 634 /* 635 * Parse a TDMA ie on station join and use it to setup node state. 636 */ 637 void 638 ieee80211_parse_tdma(struct ieee80211_node *ni, const uint8_t *ie) 639 { 640 struct ieee80211vap *vap = ni->ni_vap; 641 642 if (vap->iv_caps & IEEE80211_C_TDMA) { 643 const struct ieee80211_tdma_param *tdma = 644 (const struct ieee80211_tdma_param *)ie; 645 struct ieee80211_tdma_state *ts = vap->iv_tdma; 646 /* 647 * Adopt TDMA configuration when joining an 648 * existing network. 649 */ 650 setbit(ts->tdma_inuse, tdma->tdma_slot); 651 (void) tdma_update(vap, tdma, ni, 1); 652 /* 653 * Propagate capabilities based on the local 654 * configuration and the remote station's advertised 655 * capabilities. In particular this permits us to 656 * enable use of QoS to disable ACK's. 657 */ 658 if ((vap->iv_flags & IEEE80211_F_WME) && 659 ni->ni_ies.wme_ie != NULL) 660 ni->ni_flags |= IEEE80211_NODE_QOS; 661 } 662 } 663 664 #define TDMA_OUI_BYTES 0x00, 0x03, 0x7f 665 /* 666 * Add a TDMA parameters element to a frame. 667 */ 668 uint8_t * 669 ieee80211_add_tdma(uint8_t *frm, struct ieee80211vap *vap) 670 { 671 #define ADDSHORT(frm, v) do { \ 672 frm[0] = (v) & 0xff; \ 673 frm[1] = (v) >> 8; \ 674 frm += 2; \ 675 } while (0) 676 static const struct ieee80211_tdma_param param = { 677 .tdma_id = IEEE80211_ELEMID_VENDOR, 678 .tdma_len = sizeof(struct ieee80211_tdma_param) - 2, 679 .tdma_oui = { TDMA_OUI_BYTES }, 680 .tdma_type = TDMA_OUI_TYPE, 681 .tdma_subtype = TDMA_SUBTYPE_PARAM, 682 .tdma_version = TDMA_VERSION, 683 }; 684 const struct ieee80211_tdma_state *ts = vap->iv_tdma; 685 uint16_t slotlen; 686 687 KASSERT(vap->iv_caps & IEEE80211_C_TDMA, 688 ("not a tdma vap, caps 0x%x", vap->iv_caps)); 689 690 memcpy(frm, ¶m, sizeof(param)); 691 frm += __offsetof(struct ieee80211_tdma_param, tdma_slot); 692 *frm++ = ts->tdma_slot; 693 *frm++ = ts->tdma_slotcnt; 694 /* NB: convert units to fit in 16-bits */ 695 slotlen = ts->tdma_slotlen / 100; /* 100us units */ 696 ADDSHORT(frm, slotlen); 697 *frm++ = ts->tdma_bintval; 698 *frm++ = ts->tdma_inuse[0]; 699 frm += 10; /* pad+timestamp */ 700 return frm; 701 #undef ADDSHORT 702 } 703 #undef TDMA_OUI_BYTES 704 705 /* 706 * Update TDMA state at TBTT. 707 */ 708 void 709 ieee80211_tdma_update_beacon(struct ieee80211vap *vap, 710 struct ieee80211_beacon_offsets *bo) 711 { 712 struct ieee80211_tdma_state *ts = vap->iv_tdma; 713 714 KASSERT(vap->iv_caps & IEEE80211_C_TDMA, 715 ("not a tdma vap, caps 0x%x", vap->iv_caps)); 716 717 if (isset(bo->bo_flags, IEEE80211_BEACON_TDMA)) { 718 (void) ieee80211_add_tdma(bo->bo_tdma, vap); 719 clrbit(bo->bo_flags, IEEE80211_BEACON_TDMA); 720 } 721 if (ts->tdma_slot != 0) /* only on master */ 722 return; 723 if (ts->tdma_count <= 0) { 724 /* 725 * Time to update the mask of active/inuse stations. 726 * We track stations that we've received a beacon 727 * frame from and update this mask periodically. 728 * This allows us to miss a few beacons before marking 729 * a slot free for re-use. 730 */ 731 ts->tdma_inuse[0] = ts->tdma_active[0]; 732 ts->tdma_active[0] = 0x01; 733 /* update next time 'round */ 734 /* XXX use notify framework */ 735 setbit(bo->bo_flags, IEEE80211_BEACON_TDMA); 736 /* NB: use s/w beacon miss threshold; may be too high */ 737 ts->tdma_count = vap->iv_bmissthreshold-1; 738 } else 739 ts->tdma_count--; 740 } 741 742 static int 743 tdma_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq) 744 { 745 struct ieee80211_tdma_state *ts = vap->iv_tdma; 746 747 if ((vap->iv_caps & IEEE80211_C_TDMA) == 0) 748 return ENOSYS; 749 750 switch (ireq->i_type) { 751 case IEEE80211_IOC_TDMA_SLOT: 752 ireq->i_val = ts->tdma_slot; 753 break; 754 case IEEE80211_IOC_TDMA_SLOTCNT: 755 ireq->i_val = ts->tdma_slotcnt; 756 break; 757 case IEEE80211_IOC_TDMA_SLOTLEN: 758 ireq->i_val = ts->tdma_slotlen; 759 break; 760 case IEEE80211_IOC_TDMA_BINTERVAL: 761 ireq->i_val = ts->tdma_bintval; 762 break; 763 default: 764 return ENOSYS; 765 } 766 return 0; 767 } 768 IEEE80211_IOCTL_GET(tdma, tdma_ioctl_get80211); 769 770 static int 771 tdma_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq) 772 { 773 struct ieee80211_tdma_state *ts = vap->iv_tdma; 774 775 if ((vap->iv_caps & IEEE80211_C_TDMA) == 0) 776 return ENOSYS; 777 778 switch (ireq->i_type) { 779 case IEEE80211_IOC_TDMA_SLOT: 780 if (!(0 <= ireq->i_val && ireq->i_val <= ts->tdma_slotcnt)) 781 return EINVAL; 782 if (ireq->i_val != ts->tdma_slot) { 783 ts->tdma_slot = ireq->i_val; 784 goto restart; 785 } 786 break; 787 case IEEE80211_IOC_TDMA_SLOTCNT: 788 if (!TDMA_SLOTCNT_VALID(ireq->i_val)) 789 return EINVAL; 790 if (ireq->i_val != ts->tdma_slotcnt) { 791 ts->tdma_slotcnt = ireq->i_val; 792 goto restart; 793 } 794 break; 795 case IEEE80211_IOC_TDMA_SLOTLEN: 796 /* 797 * XXX 798 * 150 insures at least 1/8 TU 799 * 0xfffff is the max duration for bursting 800 * (implict by way of 16-bit data type for i_val) 801 */ 802 if (!TDMA_SLOTLEN_VALID(ireq->i_val)) 803 return EINVAL; 804 if (ireq->i_val != ts->tdma_slotlen) { 805 ts->tdma_slotlen = ireq->i_val; 806 goto restart; 807 } 808 break; 809 case IEEE80211_IOC_TDMA_BINTERVAL: 810 if (!TDMA_BINTVAL_VALID(ireq->i_val)) 811 return EINVAL; 812 if (ireq->i_val != ts->tdma_bintval) { 813 ts->tdma_bintval = ireq->i_val; 814 goto restart; 815 } 816 break; 817 default: 818 return ENOSYS; 819 } 820 return 0; 821 restart: 822 ieee80211_beacon_notify(vap, IEEE80211_BEACON_TDMA); 823 return ERESTART; 824 } 825 IEEE80211_IOCTL_SET(tdma, tdma_ioctl_set80211); 826 827 #endif /* IEEE80211_SUPPORT_TDMA */ 828