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