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