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