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