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