Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/net80211/ieee80211_ageq.c
39475 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2009 Sam Leffler, Errno Consulting
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
*/
27
28
#include <sys/cdefs.h>
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
}
240
241