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-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  * 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/8.0/sys/net80211/ieee80211_ageq.c 195527 2009-07-10 02:19:57Z sam $");
   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  
   38 #include <sys/socket.h>
   39 
   40 #include <net/if.h>
   41 #include <net/if_media.h>
   42 #include <net/ethernet.h>
   43 
   44 #include <net80211/ieee80211_var.h>
   45 
   46 /*
   47  * Initialize an ageq.
   48  */
   49 void
   50 ieee80211_ageq_init(struct ieee80211_ageq *aq, int maxlen, const char *name)
   51 {
   52         memset(aq, 0, sizeof(aq));
   53         aq->aq_maxlen = maxlen;
   54         IEEE80211_AGEQ_INIT(aq, name);          /* OS-dependent setup */
   55 }
   56 
   57 /*
   58  * Cleanup an ageq initialized with ieee80211_ageq_init.  Note
   59  * the queue is assumed empty; this can be done with ieee80211_ageq_drain.
   60  */
   61 void
   62 ieee80211_ageq_cleanup(struct ieee80211_ageq *aq)
   63 {
   64         KASSERT(aq->aq_len == 0, ("%d frames on ageq", aq->aq_len));
   65         IEEE80211_AGEQ_DESTROY(aq);             /* OS-dependent cleanup */
   66 }
   67 
   68 /*
   69  * Free an mbuf according to ageq rules: if marked as holding
   70  * and 802.11 frame then also reclaim a node reference from
   71  * the packet header; this handles packets q'd in the tx path.
   72  */
   73 static void
   74 ageq_mfree(struct mbuf *m)
   75 {
   76         if (m->m_flags & M_ENCAP) {
   77                 struct ieee80211_node *ni = (void *) m->m_pkthdr.rcvif;
   78                 ieee80211_free_node(ni);
   79         }
   80         m->m_nextpkt = NULL;
   81         m_freem(m);
   82 }
   83 
   84 /*
   85  * Free a list of mbufs using ageq rules (see above).
   86  */
   87 void
   88 ieee80211_ageq_mfree(struct mbuf *m)
   89 {
   90         struct mbuf *next;
   91 
   92         for (; m != NULL; m = next) {
   93                 next = m->m_nextpkt;
   94                 ageq_mfree(m);
   95         }
   96 }
   97 
   98 /*
   99  * Append an mbuf to the ageq and mark it with the specified max age
  100  * If the frame is not removed before the age (in seconds) expires
  101  * then it is reclaimed (along with any node reference).
  102  */
  103 int
  104 ieee80211_ageq_append(struct ieee80211_ageq *aq, struct mbuf *m, int age)
  105 {
  106         IEEE80211_AGEQ_LOCK(aq);
  107         if (__predict_true(aq->aq_len < aq->aq_maxlen)) {
  108                 if (aq->aq_tail == NULL) {
  109                         aq->aq_head = m;
  110                 } else {
  111                         aq->aq_tail->m_nextpkt = m;
  112                         age -= M_AGE_GET(aq->aq_head);
  113                 }
  114                 KASSERT(age >= 0, ("age %d", age));
  115                 M_AGE_SET(m, age);
  116                 m->m_nextpkt = NULL;
  117                 aq->aq_tail = m;
  118                 aq->aq_len++;
  119                 IEEE80211_AGEQ_UNLOCK(aq);
  120                 return 0;
  121         } else {
  122                 /*
  123                  * No space, drop and cleanup references.
  124                  */
  125                 aq->aq_drops++;
  126                 IEEE80211_AGEQ_UNLOCK(aq);
  127                 /* XXX tail drop? */
  128                 ageq_mfree(m);
  129                 return ENOSPC;
  130         }
  131 }
  132 
  133 /*
  134  * Drain/reclaim all frames from an ageq.
  135  */
  136 void
  137 ieee80211_ageq_drain(struct ieee80211_ageq *aq)
  138 {
  139         ieee80211_ageq_mfree(ieee80211_ageq_remove(aq, NULL));
  140 }
  141 
  142 /*
  143  * Drain/reclaim frames associated with a specific node from an ageq.
  144  */
  145 void
  146 ieee80211_ageq_drain_node(struct ieee80211_ageq *aq,
  147         struct ieee80211_node *ni)
  148 {
  149         ieee80211_ageq_mfree(ieee80211_ageq_remove(aq, ni));
  150 }
  151 
  152 /*
  153  * Age frames on the age queue.  Ages are stored as time
  154  * deltas (in seconds) relative to the head so we can check
  155  * and/or adjust only the head of the list.  If a frame's age
  156  * exceeds the time quanta then remove it.  The list of removed
  157  * frames is is returned to the caller joined by m_nextpkt.
  158  */
  159 struct mbuf *
  160 ieee80211_ageq_age(struct ieee80211_ageq *aq, int quanta)
  161 {
  162         struct mbuf *head, **phead;
  163         struct mbuf *m;
  164 
  165         phead = &head;
  166         if (aq->aq_len != 0) {
  167                 IEEE80211_AGEQ_LOCK(aq);
  168                 while ((m = aq->aq_head) != NULL && M_AGE_GET(m) < quanta) {
  169                         if ((aq->aq_head = m->m_nextpkt) == NULL)
  170                                 aq->aq_tail = NULL;
  171                         KASSERT(aq->aq_len > 0, ("aq len %d", aq->aq_len));
  172                         aq->aq_len--;
  173                         /* add to private list for return */
  174                         *phead = m;
  175                         phead = &m->m_nextpkt;
  176                 }
  177                 if (m != NULL)
  178                         M_AGE_SUB(m, quanta);
  179                 IEEE80211_AGEQ_UNLOCK(aq);
  180         }
  181         *phead = NULL;
  182         return head;
  183 }
  184 
  185 /*
  186  * Remove all frames matching the specified node identifier
  187  * (NULL matches all).  Frames are returned as a list joined
  188  * by m_nextpkt.
  189  */
  190 struct mbuf *
  191 ieee80211_ageq_remove(struct ieee80211_ageq *aq,
  192         struct ieee80211_node *match)
  193 {
  194         struct mbuf *m, **prev, *ohead;
  195         struct mbuf *head, **phead;
  196 
  197         IEEE80211_AGEQ_LOCK(aq);
  198         ohead = aq->aq_head;
  199         prev = &aq->aq_head;
  200         phead = &head;
  201         while ((m = *prev) != NULL) {
  202                 if (match != NULL && m->m_pkthdr.rcvif != (void *) match) {
  203                         prev = &m->m_nextpkt;
  204                         continue;
  205                 }
  206                 /*
  207                  * Adjust q length.
  208                  */
  209                 KASSERT(aq->aq_len > 0, ("aq len %d", aq->aq_len));
  210                 aq->aq_len--;
  211                 /*
  212                  * Remove from forward list; tail pointer is harder.
  213                  */
  214                 if (aq->aq_tail == m) {
  215                         KASSERT(m->m_nextpkt == NULL, ("not last"));
  216                         if (aq->aq_head == m) {         /* list empty */
  217                                 KASSERT(aq->aq_len == 0,
  218                                     ("not empty, len %d", aq->aq_len));
  219                                 aq->aq_tail = NULL;
  220                         } else {                        /* must be one before */
  221                                 aq->aq_tail = (struct mbuf *)((uintptr_t)prev -
  222                                     offsetof(struct mbuf, m_nextpkt));
  223                         }
  224                 }
  225                 *prev = m->m_nextpkt;
  226 
  227                 /* add to private list for return */
  228                 *phead = m;
  229                 phead = &m->m_nextpkt;
  230         }
  231         if (head == ohead && aq->aq_head != NULL)       /* correct age */
  232                 M_AGE_SET(aq->aq_head, M_AGE_GET(head));
  233         IEEE80211_AGEQ_UNLOCK(aq);
  234 
  235         *phead = NULL;
  236         return head;
  237 }

Cache object: 85fdea5d647bbf903a4422141dc2c65e


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