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