The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net80211/ieee80211_tdma.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: d2ad1690ec17d853652f36579ebfd105


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.