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