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_ageq.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2009 Sam Leffler, Errno Consulting
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   24  */
   25 
   26 #include <sys/cdefs.h>
   27 __FBSDID("$FreeBSD: releng/11.0/sys/net80211/ieee80211_ageq.c 295126 2016-02-01 17:41:21Z glebius $");
   28 
   29 /*
   30  * IEEE 802.11 age queue support.
   31  */
   32 #include "opt_wlan.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h> 
   36 #include <sys/kernel.h>
   37 #include <sys/malloc.h>
   38  
   39 #include <sys/socket.h>
   40 
   41 #include <net/if.h>
   42 #include <net/if_var.h>
   43 #include <net/if_media.h>
   44 #include <net/ethernet.h>
   45 
   46 #include <net80211/ieee80211_var.h>
   47 
   48 /*
   49  * Initialize an ageq.
   50  */
   51 void
   52 ieee80211_ageq_init(struct ieee80211_ageq *aq, int maxlen, const char *name)
   53 {
   54         memset(aq, 0, sizeof(*aq));
   55         aq->aq_maxlen = maxlen;
   56         IEEE80211_AGEQ_INIT(aq, name);          /* OS-dependent setup */
   57 }
   58 
   59 /*
   60  * Cleanup an ageq initialized with ieee80211_ageq_init.  Note
   61  * the queue is assumed empty; this can be done with ieee80211_ageq_drain.
   62  */
   63 void
   64 ieee80211_ageq_cleanup(struct ieee80211_ageq *aq)
   65 {
   66         KASSERT(aq->aq_len == 0, ("%d frames on ageq", aq->aq_len));
   67         IEEE80211_AGEQ_DESTROY(aq);             /* OS-dependent cleanup */
   68 }
   69 
   70 /*
   71  * Free an mbuf according to ageq rules: if marked as holding
   72  * and 802.11 frame then also reclaim a node reference from
   73  * the packet header; this handles packets q'd in the tx path.
   74  */
   75 static void
   76 ageq_mfree(struct mbuf *m)
   77 {
   78         if (m->m_flags & M_ENCAP) {
   79                 struct ieee80211_node *ni = (void *) m->m_pkthdr.rcvif;
   80                 ieee80211_free_node(ni);
   81         }
   82         m->m_nextpkt = NULL;
   83         m_freem(m);
   84 }
   85 
   86 /*
   87  * Free a list of mbufs using ageq rules (see above).
   88  */
   89 void
   90 ieee80211_ageq_mfree(struct mbuf *m)
   91 {
   92         struct mbuf *next;
   93 
   94         for (; m != NULL; m = next) {
   95                 next = m->m_nextpkt;
   96                 ageq_mfree(m);
   97         }
   98 }
   99 
  100 /*
  101  * Append an mbuf to the ageq and mark it with the specified max age
  102  * If the frame is not removed before the age (in seconds) expires
  103  * then it is reclaimed (along with any node reference).
  104  */
  105 int
  106 ieee80211_ageq_append(struct ieee80211_ageq *aq, struct mbuf *m, int age)
  107 {
  108         IEEE80211_AGEQ_LOCK(aq);
  109         if (__predict_true(aq->aq_len < aq->aq_maxlen)) {
  110                 if (aq->aq_tail == NULL) {
  111                         aq->aq_head = m;
  112                 } else {
  113                         aq->aq_tail->m_nextpkt = m;
  114                         age -= M_AGE_GET(aq->aq_head);
  115                 }
  116                 KASSERT(age >= 0, ("age %d", age));
  117                 M_AGE_SET(m, age);
  118                 m->m_nextpkt = NULL;
  119                 aq->aq_tail = m;
  120                 aq->aq_len++;
  121                 IEEE80211_AGEQ_UNLOCK(aq);
  122                 return 0;
  123         } else {
  124                 /*
  125                  * No space, drop and cleanup references.
  126                  */
  127                 aq->aq_drops++;
  128                 IEEE80211_AGEQ_UNLOCK(aq);
  129                 /* XXX tail drop? */
  130                 ageq_mfree(m);
  131                 return ENOSPC;
  132         }
  133 }
  134 
  135 /*
  136  * Drain/reclaim all frames from an ageq.
  137  */
  138 void
  139 ieee80211_ageq_drain(struct ieee80211_ageq *aq)
  140 {
  141         ieee80211_ageq_mfree(ieee80211_ageq_remove(aq, NULL));
  142 }
  143 
  144 /*
  145  * Drain/reclaim frames associated with a specific node from an ageq.
  146  */
  147 void
  148 ieee80211_ageq_drain_node(struct ieee80211_ageq *aq,
  149         struct ieee80211_node *ni)
  150 {
  151         ieee80211_ageq_mfree(ieee80211_ageq_remove(aq, ni));
  152 }
  153 
  154 /*
  155  * Age frames on the age queue.  Ages are stored as time
  156  * deltas (in seconds) relative to the head so we can check
  157  * and/or adjust only the head of the list.  If a frame's age
  158  * exceeds the time quanta then remove it.  The list of removed
  159  * frames is returned to the caller joined by m_nextpkt.
  160  */
  161 struct mbuf *
  162 ieee80211_ageq_age(struct ieee80211_ageq *aq, int quanta)
  163 {
  164         struct mbuf *head, **phead;
  165         struct mbuf *m;
  166 
  167         phead = &head;
  168         if (aq->aq_len != 0) {
  169                 IEEE80211_AGEQ_LOCK(aq);
  170                 while ((m = aq->aq_head) != NULL && M_AGE_GET(m) < quanta) {
  171                         if ((aq->aq_head = m->m_nextpkt) == NULL)
  172                                 aq->aq_tail = NULL;
  173                         KASSERT(aq->aq_len > 0, ("aq len %d", aq->aq_len));
  174                         aq->aq_len--;
  175                         /* add to private list for return */
  176                         *phead = m;
  177                         phead = &m->m_nextpkt;
  178                 }
  179                 if (m != NULL)
  180                         M_AGE_SUB(m, quanta);
  181                 IEEE80211_AGEQ_UNLOCK(aq);
  182         }
  183         *phead = NULL;
  184         return head;
  185 }
  186 
  187 /*
  188  * Remove all frames matching the specified node identifier
  189  * (NULL matches all).  Frames are returned as a list joined
  190  * by m_nextpkt.
  191  */
  192 struct mbuf *
  193 ieee80211_ageq_remove(struct ieee80211_ageq *aq,
  194         struct ieee80211_node *match)
  195 {
  196         struct mbuf *m, **prev, *ohead;
  197         struct mbuf *head, **phead;
  198 
  199         IEEE80211_AGEQ_LOCK(aq);
  200         ohead = aq->aq_head;
  201         prev = &aq->aq_head;
  202         phead = &head;
  203         while ((m = *prev) != NULL) {
  204                 if (match != NULL && m->m_pkthdr.rcvif != (void *) match) {
  205                         prev = &m->m_nextpkt;
  206                         continue;
  207                 }
  208                 /*
  209                  * Adjust q length.
  210                  */
  211                 KASSERT(aq->aq_len > 0, ("aq len %d", aq->aq_len));
  212                 aq->aq_len--;
  213                 /*
  214                  * Remove from forward list; tail pointer is harder.
  215                  */
  216                 if (aq->aq_tail == m) {
  217                         KASSERT(m->m_nextpkt == NULL, ("not last"));
  218                         if (aq->aq_head == m) {         /* list empty */
  219                                 KASSERT(aq->aq_len == 0,
  220                                     ("not empty, len %d", aq->aq_len));
  221                                 aq->aq_tail = NULL;
  222                         } else {                        /* must be one before */
  223                                 aq->aq_tail = (struct mbuf *)((uintptr_t)prev -
  224                                     offsetof(struct mbuf, m_nextpkt));
  225                         }
  226                 }
  227                 *prev = m->m_nextpkt;
  228 
  229                 /* add to private list for return */
  230                 *phead = m;
  231                 phead = &m->m_nextpkt;
  232         }
  233         if (head == ohead && aq->aq_head != NULL)       /* correct age */
  234                 M_AGE_SET(aq->aq_head, M_AGE_GET(head));
  235         IEEE80211_AGEQ_UNLOCK(aq);
  236 
  237         *phead = NULL;
  238         return head;
  239 }

Cache object: 3020be3f1f299ccac71fa3cbf33c5cd2


[ 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.