ieee80211_tdma.c revision 188782
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 188782 2009-02-19 05:21:54Z 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_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 /* 245 * Start s/w beacon miss timer for slave devices w/o 246 * hardware support. The 2x is a fudge for our doing 247 * this in software. 248 */ 249 vap->iv_swbmiss_period = IEEE80211_TU_TO_TICKS( 250 2 * vap->iv_bmissthreshold * ts->tdma_bintval * 251 ((ts->tdma_slotcnt * ts->tdma_slotlen) / 1024)); 252 vap->iv_swbmiss_count = 0; 253 callout_reset(&vap->iv_swbmiss, vap->iv_swbmiss_period, 254 ieee80211_swbmiss, vap); 255 } 256 return status; 257} 258 259static void 260tdma_beacon_miss(struct ieee80211vap *vap) 261{ 262 struct ieee80211_tdma_state *ts = vap->iv_tdma; 263 264 KASSERT((vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0, ("scanning")); 265 KASSERT(vap->iv_state == IEEE80211_S_RUN, 266 ("wrong state %d", vap->iv_state)); 267 268 IEEE80211_DPRINTF(vap, 269 IEEE80211_MSG_STATE | IEEE80211_MSG_TDMA | IEEE80211_MSG_DEBUG, 270 "beacon miss, mode %u state %s\n", 271 vap->iv_opmode, ieee80211_state_name[vap->iv_state]); 272 273 if (ts->tdma_peer != NULL) { /* XXX? can this be null? */ 274 ieee80211_notify_node_leave(vap->iv_bss); 275 ts->tdma_peer = NULL; 276 /* 277 * Treat beacon miss like an associate failure wrt the 278 * scan policy; this forces the entry in the scan cache 279 * to be ignored after several tries. 280 */ 281 ieee80211_scan_assoc_fail(vap, vap->iv_bss->ni_macaddr, 282 IEEE80211_STATUS_TIMEOUT); 283 } 284#if 0 285 ts->tdma_inuse = 0; /* clear slot usage */ 286#endif 287 ieee80211_new_state(vap, IEEE80211_S_SCAN, 0); 288} 289 290static void 291tdma_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, 292 int subtype, int rssi, int noise, uint32_t rstamp) 293{ 294 struct ieee80211com *ic = ni->ni_ic; 295 struct ieee80211vap *vap = ni->ni_vap; 296 struct ieee80211_tdma_state *ts = vap->iv_tdma; 297 298 if (subtype == IEEE80211_FC0_SUBTYPE_BEACON && 299 (ic->ic_flags & IEEE80211_F_SCAN) == 0) { 300 struct ieee80211_frame *wh = mtod(m0, struct ieee80211_frame *); 301 struct ieee80211_scanparams scan; 302 303 if (ieee80211_parse_beacon(ni, m0, &scan) != 0) 304 return; 305 if (scan.tdma == NULL) { 306 /* 307 * TDMA stations must beacon a TDMA ie; ignore 308 * any other station. 309 * XXX detect overlapping bss and change channel 310 */ 311 IEEE80211_DISCARD(vap, 312 IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT, 313 wh, ieee80211_mgt_subtype_name[subtype >> 314 IEEE80211_FC0_SUBTYPE_SHIFT], 315 "%s", "no TDMA ie"); 316 vap->iv_stats.is_rx_mgtdiscard++; 317 return; 318 } 319 if (ni == vap->iv_bss && 320 !IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) { 321 /* 322 * Fake up a node for this newly 323 * discovered member of the IBSS. 324 */ 325 ni = ieee80211_add_neighbor(vap, wh, &scan); 326 if (ni == NULL) { 327 /* NB: stat kept for alloc failure */ 328 return; 329 } 330 } 331 /* 332 * Check for state updates. 333 */ 334 if (IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid)) { 335 /* 336 * Count frame now that we know it's to be processed. 337 */ 338 vap->iv_stats.is_rx_beacon++; 339 IEEE80211_NODE_STAT(ni, rx_beacons); 340 /* 341 * Record tsf of last beacon. NB: this must be 342 * done before calling tdma_process_params 343 * as deeper routines reference it. 344 */ 345 memcpy(&ni->ni_tstamp.data, scan.tstamp, 346 sizeof(ni->ni_tstamp.data)); 347 /* 348 * Count beacon frame for s/w bmiss handling. 349 */ 350 vap->iv_swbmiss_count++; 351 /* 352 * Process tdma ie. The contents are used to sync 353 * the slot timing, reconfigure the bss, etc. 354 */ 355 (void) tdma_process_params(ni, scan.tdma, rstamp, wh); 356 return; 357 } 358 /* 359 * NB: defer remaining work to the adhoc code; this causes 360 * 2x parsing of the frame but should happen infrequently 361 */ 362 } 363 ts->tdma_recv_mgmt(ni, m0, subtype, rssi, noise, rstamp); 364} 365 366/* 367 * Update TDMA state on receipt of a beacon frame with 368 * a TDMA information element. The sender's identity 369 * is provided so we can track who our peer is. If pickslot 370 * is non-zero we scan the slot allocation state in the ie 371 * locate a free slot for our use. 372 */ 373static int 374tdma_update(struct ieee80211vap *vap, const struct ieee80211_tdma_param *tdma, 375 struct ieee80211_node *ni, int pickslot) 376{ 377 struct ieee80211_tdma_state *ts = vap->iv_tdma; 378 int slotlen, slotcnt, slot, bintval; 379 380 KASSERT(vap->iv_caps & IEEE80211_C_TDMA, 381 ("not a tdma vap, caps 0x%x", vap->iv_caps)); 382 383 slotlen = le16toh(tdma->tdma_slotlen); 384 slotcnt = tdma->tdma_slotcnt; 385 bintval = tdma->tdma_bintval; 386 387 /* XXX rate-limit printf's */ 388 if (!(2 <= slotcnt && slotcnt <= IEEE80211_TDMA_MAXSLOTS)) { 389 printf("%s: bogus slot cnt %u\n", __func__, slotcnt); 390 return 0; 391 } 392 /* XXX magic constants */ 393 if (slotlen < 2 || slotlen > (0xfffff/100)) { 394 printf("%s: bogus slot len %u\n", __func__, slotlen); 395 return 0; 396 } 397 if (bintval < 1) { 398 printf("%s: bogus beacon interval %u\n", __func__, bintval); 399 return 0; 400 } 401 if (pickslot) { 402 /* 403 * Pick unoccupied slot. Note we never choose slot 0. 404 */ 405 for (slot = slotcnt-1; slot > 0; slot--) 406 if (isclr(tdma->tdma_inuse, slot)) 407 break; 408 if (slot <= 0) { 409 printf("%s: no free slot, slotcnt %u inuse: 0x%x\n", 410 __func__, slotcnt, tdma->tdma_inuse[0]); 411 /* XXX need to do something better */ 412 return 0; 413 } 414 } else 415 slot = ts->tdma_slot; 416 417 if (slotcnt != ts->tdma_slotcnt || 418 100*slotlen != ts->tdma_slotlen || 419 bintval != ts->tdma_bintval || 420 slot != ts->tdma_slot || 421 ts->tdma_peer != ni) { 422 /* 423 * New/changed parameters; update runtime state. 424 */ 425 /* XXX overwrites user parameters */ 426 ts->tdma_slotcnt = slotcnt; 427 ts->tdma_slotlen = 100*slotlen; 428 ts->tdma_slot = slot; 429 ts->tdma_bintval = bintval; 430 /* mark beacon to be updated before next xmit */ 431 ieee80211_beacon_notify(vap, IEEE80211_BEACON_TDMA); 432 433 IEEE80211_DPRINTF(vap, IEEE80211_MSG_TDMA, 434 "%s: slot %u slotcnt %u slotlen %u us bintval %u\n", 435 __func__, slot, slotcnt, 100*slotlen, tdma->tdma_bintval); 436 } 437 /* 438 * Notify driver. Note we can be called before 439 * entering RUN state if we scanned and are 440 * joining an existing bss. In that case do not 441 * call the driver because not all necessary state 442 * has been setup. The next beacon will dtrt. 443 */ 444 if (vap->iv_state == IEEE80211_S_RUN) 445 vap->iv_ic->ic_tdma_update(ni, tdma); 446 /* 447 * Dispatch join event on first beacon from new master. 448 */ 449 if (ts->tdma_peer != ni) { 450 if (ts->tdma_peer != NULL) 451 ieee80211_notify_node_leave(vap->iv_bss); 452 ieee80211_notify_node_join(ni, 1); 453 /* NB: no reference, we just use the address */ 454 ts->tdma_peer = ni; 455 } 456 return 1; 457} 458 459/* 460 * Process received TDMA parameters. 461 */ 462static int 463tdma_process_params(struct ieee80211_node *ni, 464 const u_int8_t *ie, u_int32_t rstamp, const struct ieee80211_frame *wh) 465{ 466 struct ieee80211vap *vap = ni->ni_vap; 467 struct ieee80211_tdma_state *ts = vap->iv_tdma; 468 const struct ieee80211_tdma_param *tdma = 469 (const struct ieee80211_tdma_param *) ie; 470 u_int len = ie[1]; 471 472 KASSERT(vap->iv_caps & IEEE80211_C_TDMA, 473 ("not a tdma vap, caps 0x%x", vap->iv_caps)); 474 475 if (len < sizeof(*tdma) - 2) { 476 IEEE80211_DISCARD_IE(vap, 477 IEEE80211_MSG_ELEMID | IEEE80211_MSG_TDMA, 478 wh, "tdma", "too short, len %u", len); 479 return IEEE80211_REASON_IE_INVALID; 480 } 481 if (tdma->tdma_version != TDMA_VERSION) { 482 IEEE80211_DISCARD_IE(vap, 483 IEEE80211_MSG_ELEMID | IEEE80211_MSG_TDMA, 484 wh, "tdma", "bad version %u", tdma->tdma_version); 485 return IEEE80211_REASON_IE_INVALID; 486 } 487 /* 488 * Can reach here while scanning, update 489 * operational state only in RUN state. 490 */ 491 if (vap->iv_state == IEEE80211_S_RUN) { 492 if (tdma->tdma_slot != ts->tdma_slot && 493 isclr(ts->tdma_inuse, tdma->tdma_slot)) { 494 IEEE80211_NOTE(vap, IEEE80211_MSG_TDMA, ni, 495 "discovered in slot %u", tdma->tdma_slot); 496 setbit(ts->tdma_inuse, tdma->tdma_slot); 497 /* XXX dispatch event only when operating as master */ 498 if (ts->tdma_slot == 0) 499 ieee80211_notify_node_join(ni, 1); 500 } 501 setbit(ts->tdma_active, tdma->tdma_slot); 502 if (tdma->tdma_slot == ts->tdma_slot-1) { 503 /* 504 * Slave tsf synchronization to station 505 * just before us in the schedule. The driver 506 * is responsible for copying the timestamp 507 * of the received beacon into our beacon 508 * frame so the sender can calculate round 509 * trip time. We cannot do that here because 510 * we don't know how to update our beacon frame. 511 */ 512 (void) tdma_update(vap, tdma, ni, 0); 513 /* XXX reschedule swbmiss timer on parameter change */ 514 } else if (tdma->tdma_slot == ts->tdma_slot+1) { 515 uint64_t tstamp; 516 int32_t rtt; 517 /* 518 * Use returned timstamp to calculate the 519 * roundtrip time. 520 */ 521 memcpy(&tstamp, tdma->tdma_tstamp, 8); 522 /* XXX use only 15 bits of rstamp */ 523 rtt = rstamp - (le64toh(tstamp) & 0x7fff); 524 if (rtt < 0) 525 rtt += 0x7fff; 526 /* XXX hack to quiet normal use */ 527 IEEE80211_DPRINTF(vap, IEEE80211_MSG_DOT1X, 528 "tdma rtt %5u [rstamp %5u tstamp %llu]\n", 529 rtt, rstamp, 530 (unsigned long long) le64toh(tstamp)); 531 } else if (tdma->tdma_slot == ts->tdma_slot && 532 le64toh(ni->ni_tstamp.tsf) > vap->iv_bss->ni_tstamp.tsf) { 533 /* 534 * Station using the same slot as us and has 535 * been around longer than us; we must move. 536 * Note this can happen if stations do not 537 * see each other while scanning. 538 */ 539 IEEE80211_DPRINTF(vap, IEEE80211_MSG_TDMA, 540 "slot %u collision rxtsf %llu tsf %llu\n", 541 tdma->tdma_slot, 542 (unsigned long long) le64toh(ni->ni_tstamp.tsf), 543 vap->iv_bss->ni_tstamp.tsf); 544 setbit(ts->tdma_inuse, tdma->tdma_slot); 545 546 (void) tdma_update(vap, tdma, ni, 1); 547 } 548 } 549 return 0; 550} 551 552int 553ieee80211_tdma_getslot(struct ieee80211vap *vap) 554{ 555 struct ieee80211_tdma_state *ts = vap->iv_tdma; 556 557 KASSERT(vap->iv_caps & IEEE80211_C_TDMA, 558 ("not a tdma vap, caps 0x%x", vap->iv_caps)); 559 return ts->tdma_slot; 560} 561 562/* 563 * Parse a TDMA ie on station join and use it to setup node state. 564 */ 565void 566ieee80211_parse_tdma(struct ieee80211_node *ni, const uint8_t *ie) 567{ 568 struct ieee80211vap *vap = ni->ni_vap; 569 570 if (vap->iv_caps & IEEE80211_C_TDMA) { 571 const struct ieee80211_tdma_param *tdma = 572 (const struct ieee80211_tdma_param *)ie; 573 struct ieee80211_tdma_state *ts = vap->iv_tdma; 574 /* 575 * Adopt TDMA configuration when joining an 576 * existing network. 577 */ 578 setbit(ts->tdma_inuse, tdma->tdma_slot); 579 (void) tdma_update(vap, tdma, ni, 1); 580 /* 581 * Propagate capabilities based on the local 582 * configuration and the remote station's advertised 583 * capabilities. In particular this permits us to 584 * enable use of QoS to disable ACK's. 585 */ 586 if ((vap->iv_flags & IEEE80211_F_WME) && 587 ni->ni_ies.wme_ie != NULL) 588 ni->ni_flags |= IEEE80211_NODE_QOS; 589 } 590} 591 592#define TDMA_OUI_BYTES 0x00, 0x03, 0x7f 593/* 594 * Add a TDMA parameters element to a frame. 595 */ 596uint8_t * 597ieee80211_add_tdma(uint8_t *frm, struct ieee80211vap *vap) 598{ 599#define ADDSHORT(frm, v) do { \ 600 frm[0] = (v) & 0xff; \ 601 frm[1] = (v) >> 8; \ 602 frm += 2; \ 603} while (0) 604 static const struct ieee80211_tdma_param param = { 605 .tdma_id = IEEE80211_ELEMID_VENDOR, 606 .tdma_len = sizeof(struct ieee80211_tdma_param) - 2, 607 .tdma_oui = { TDMA_OUI_BYTES }, 608 .tdma_type = TDMA_OUI_TYPE, 609 .tdma_subtype = TDMA_SUBTYPE_PARAM, 610 .tdma_version = TDMA_VERSION, 611 }; 612 const struct ieee80211_tdma_state *tdma = vap->iv_tdma; 613 uint16_t slotlen; 614 615 KASSERT(vap->iv_caps & IEEE80211_C_TDMA, 616 ("not a tdma vap, caps 0x%x", vap->iv_caps)); 617 618 memcpy(frm, ¶m, sizeof(param)); 619 frm += __offsetof(struct ieee80211_tdma_param, tdma_slot); 620 *frm++ = tdma->tdma_slot; 621 *frm++ = tdma->tdma_slotcnt; 622 /* NB: convert units to fit in 16-bits */ 623 slotlen = tdma->tdma_slotlen / 100; /* 100us units */ 624 ADDSHORT(frm, slotlen); 625 *frm++ = tdma->tdma_bintval; 626 *frm++ = tdma->tdma_inuse[0]; 627 frm += 10; /* pad+timestamp */ 628 return frm; 629#undef ADDSHORT 630} 631#undef TDMA_OUI_BYTES 632 633/* 634 * Update TDMA state at TBTT. 635 */ 636void 637ieee80211_tdma_update_beacon(struct ieee80211vap *vap, 638 struct ieee80211_beacon_offsets *bo) 639{ 640 struct ieee80211_tdma_state *ts = vap->iv_tdma; 641 642 KASSERT(vap->iv_caps & IEEE80211_C_TDMA, 643 ("not a tdma vap, caps 0x%x", vap->iv_caps)); 644 645 if (isset(bo->bo_flags, IEEE80211_BEACON_TDMA)) { 646 (void) ieee80211_add_tdma(bo->bo_tdma, vap); 647 clrbit(bo->bo_flags, IEEE80211_BEACON_TDMA); 648 } 649 if (ts->tdma_slot != 0) /* only on master */ 650 return; 651 if (ts->tdma_count <= 0) { 652 /* 653 * Time to update the mask of active/inuse stations. 654 * We track stations that we've received a beacon 655 * frame from and update this mask periodically. 656 * This allows us to miss a few beacons before marking 657 * a slot free for re-use. 658 */ 659 ts->tdma_inuse[0] = ts->tdma_active[0]; 660 ts->tdma_active[0] = 0x01; 661 /* update next time 'round */ 662 /* XXX use notify framework */ 663 setbit(bo->bo_flags, IEEE80211_BEACON_TDMA); 664 /* NB: use s/w beacon miss threshold; may be too high */ 665 ts->tdma_count = vap->iv_bmissthreshold-1; 666 } else 667 ts->tdma_count--; 668} 669 670int 671ieee80211_tdma_ioctl_get80211(struct ieee80211vap *vap, 672 struct ieee80211req *ireq) 673{ 674 struct ieee80211_tdma_state *ts = vap->iv_tdma; 675 676 if ((vap->iv_caps & IEEE80211_C_TDMA) == 0) 677 return EOPNOTSUPP; 678 679 switch (ireq->i_type) { 680 case IEEE80211_IOC_TDMA_SLOT: 681 ireq->i_val = ts->tdma_slot; 682 break; 683 case IEEE80211_IOC_TDMA_SLOTCNT: 684 ireq->i_val = ts->tdma_slotcnt; 685 break; 686 case IEEE80211_IOC_TDMA_SLOTLEN: 687 ireq->i_val = ts->tdma_slotlen; 688 break; 689 case IEEE80211_IOC_TDMA_BINTERVAL: 690 ireq->i_val = ts->tdma_bintval; 691 break; 692 default: 693 return EINVAL; 694 } 695 return 0; 696} 697 698int 699ieee80211_tdma_ioctl_set80211(struct ieee80211vap *vap, 700 struct ieee80211req *ireq) 701{ 702 struct ieee80211_tdma_state *ts = vap->iv_tdma; 703 704 if ((vap->iv_caps & IEEE80211_C_TDMA) == 0) 705 return EOPNOTSUPP; 706 707 switch (ireq->i_type) { 708 case IEEE80211_IOC_TDMA_SLOT: 709 if (!(0 <= ireq->i_val && ireq->i_val <= ts->tdma_slotcnt)) 710 return EINVAL; 711 if (ireq->i_val != ts->tdma_slot) { 712 ts->tdma_slot = ireq->i_val; 713 return ERESTART; 714 } 715 break; 716 case IEEE80211_IOC_TDMA_SLOTCNT: 717 if (!(2 <= ireq->i_val && 718 ireq->i_val <= IEEE80211_TDMA_MAXSLOTS)) 719 return EINVAL; 720 if (ireq->i_val != ts->tdma_slotcnt) { 721 ts->tdma_slotcnt = ireq->i_val; 722 return ERESTART; 723 } 724 break; 725 case IEEE80211_IOC_TDMA_SLOTLEN: 726 /* 727 * XXX 728 * 150 insures at least 1/8 TU 729 * 0xfffff is the max duration for bursting 730 * (implict by way of 16-bit data type for i_val) 731 */ 732 if (ireq->i_val < 150) 733 return EINVAL; 734 if (ireq->i_val != ts->tdma_slotlen) { 735 ts->tdma_slotlen = ireq->i_val; 736 return ERESTART; 737 } 738 break; 739 case IEEE80211_IOC_TDMA_BINTERVAL: 740 if (ireq->i_val < 1) 741 return EINVAL; 742 if (ireq->i_val != ts->tdma_bintval) { 743 ts->tdma_bintval = ireq->i_val; 744 return ERESTART; 745 } 746 break; 747 default: 748 return EINVAL; 749 } 750 return 0; 751} 752#endif /* IEEE80211_SUPPORT_TDMA */ 753