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