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#ifdef __FreeBSD__
28__FBSDID("$FreeBSD: stable/11/sys/net80211/ieee80211_action.c 330470 2018-03-05 08:37:08Z eadler $");
29#endif
30
31/*
32 * IEEE 802.11 send/recv action frame support.
33 */
34
35#include "opt_inet.h"
36#include "opt_wlan.h"
37
38#include <sys/param.h>
39#include <sys/kernel.h>
40#include <sys/malloc.h>
41#include <sys/systm.h>
42
43#include <sys/socket.h>
44
45#include <net/if.h>
46#include <net/if_var.h>
47#include <net/if_media.h>
48#include <net/ethernet.h>
49
50#include <net80211/ieee80211_var.h>
51#include <net80211/ieee80211_action.h>
52#include <net80211/ieee80211_mesh.h>
53
54static int
55send_inval(struct ieee80211_node *ni, int cat, int act, void *sa)
56{
57	return EINVAL;
58}
59
60static ieee80211_send_action_func *ba_send_action[8] = {
61	send_inval, send_inval, send_inval, send_inval,
62	send_inval, send_inval, send_inval, send_inval,
63};
64static ieee80211_send_action_func *ht_send_action[8] = {
65	send_inval, send_inval, send_inval, send_inval,
66	send_inval, send_inval, send_inval, send_inval,
67};
68static ieee80211_send_action_func *meshpl_send_action[8] = {
69	send_inval, send_inval, send_inval, send_inval,
70	send_inval, send_inval, send_inval, send_inval,
71};
72static ieee80211_send_action_func *meshaction_send_action[12] = {
73	send_inval, send_inval, send_inval, send_inval,
74	send_inval, send_inval, send_inval, send_inval,
75	send_inval, send_inval, send_inval, send_inval,
76};
77static ieee80211_send_action_func *vendor_send_action[8] = {
78	send_inval, send_inval, send_inval, send_inval,
79	send_inval, send_inval, send_inval, send_inval,
80};
81
82static ieee80211_send_action_func *vht_send_action[3] = {
83	send_inval, send_inval, send_inval,
84};
85
86int
87ieee80211_send_action_register(int cat, int act, ieee80211_send_action_func *f)
88{
89	switch (cat) {
90	case IEEE80211_ACTION_CAT_BA:
91		if (act >= nitems(ba_send_action))
92			break;
93		ba_send_action[act] = f;
94		return 0;
95	case IEEE80211_ACTION_CAT_HT:
96		if (act >= nitems(ht_send_action))
97			break;
98		ht_send_action[act] = f;
99		return 0;
100	case IEEE80211_ACTION_CAT_SELF_PROT:
101		if (act >= nitems(meshpl_send_action))
102			break;
103		meshpl_send_action[act] = f;
104		return 0;
105	case IEEE80211_ACTION_CAT_MESH:
106		if (act >= nitems(meshaction_send_action))
107			break;
108		meshaction_send_action[act] = f;
109		return 0;
110	case IEEE80211_ACTION_CAT_VENDOR:
111		if (act >= nitems(vendor_send_action))
112			break;
113		vendor_send_action[act] = f;
114		return 0;
115	case IEEE80211_ACTION_CAT_VHT:
116		if (act >= nitems(vht_send_action))
117			break;
118		vht_send_action[act] = f;
119		return 0;
120	}
121	return EINVAL;
122}
123
124void
125ieee80211_send_action_unregister(int cat, int act)
126{
127	ieee80211_send_action_register(cat, act, send_inval);
128}
129
130int
131ieee80211_send_action(struct ieee80211_node *ni, int cat, int act, void *sa)
132{
133	ieee80211_send_action_func *f = send_inval;
134
135	switch (cat) {
136	case IEEE80211_ACTION_CAT_BA:
137		if (act < nitems(ba_send_action))
138			f = ba_send_action[act];
139		break;
140	case IEEE80211_ACTION_CAT_HT:
141		if (act < nitems(ht_send_action))
142			f = ht_send_action[act];
143		break;
144	case IEEE80211_ACTION_CAT_SELF_PROT:
145		if (act < nitems(meshpl_send_action))
146			f = meshpl_send_action[act];
147		break;
148	case IEEE80211_ACTION_CAT_MESH:
149		if (act < nitems(meshaction_send_action))
150			f = meshaction_send_action[act];
151		break;
152	case IEEE80211_ACTION_CAT_VENDOR:
153		if (act < nitems(vendor_send_action))
154			f = vendor_send_action[act];
155		break;
156	case IEEE80211_ACTION_CAT_VHT:
157		if (act < nitems(vht_send_action))
158			f = vht_send_action[act];
159		break;
160	}
161	return f(ni, cat, act, sa);
162}
163
164static int
165recv_inval(struct ieee80211_node *ni, const struct ieee80211_frame *wh,
166	const uint8_t *frm, const uint8_t *efrm)
167{
168	return EINVAL;
169}
170
171static ieee80211_recv_action_func *ba_recv_action[8] = {
172	recv_inval, recv_inval, recv_inval, recv_inval,
173	recv_inval, recv_inval, recv_inval, recv_inval,
174};
175static ieee80211_recv_action_func *ht_recv_action[8] = {
176	recv_inval, recv_inval, recv_inval, recv_inval,
177	recv_inval, recv_inval, recv_inval, recv_inval,
178};
179static ieee80211_recv_action_func *meshpl_recv_action[8] = {
180	recv_inval, recv_inval, recv_inval, recv_inval,
181	recv_inval, recv_inval, recv_inval, recv_inval,
182};
183static ieee80211_recv_action_func *meshaction_recv_action[12] = {
184	recv_inval, recv_inval, recv_inval, recv_inval,
185	recv_inval, recv_inval, recv_inval, recv_inval,
186	recv_inval, recv_inval, recv_inval, recv_inval,
187};
188static ieee80211_recv_action_func *vendor_recv_action[8] = {
189	recv_inval, recv_inval, recv_inval, recv_inval,
190	recv_inval, recv_inval, recv_inval, recv_inval,
191};
192
193static ieee80211_recv_action_func *vht_recv_action[3] = {
194	recv_inval, recv_inval, recv_inval
195};
196
197int
198ieee80211_recv_action_register(int cat, int act, ieee80211_recv_action_func *f)
199{
200	switch (cat) {
201	case IEEE80211_ACTION_CAT_BA:
202		if (act >= nitems(ba_recv_action))
203			break;
204		ba_recv_action[act] = f;
205		return 0;
206	case IEEE80211_ACTION_CAT_HT:
207		if (act >= nitems(ht_recv_action))
208			break;
209		ht_recv_action[act] = f;
210		return 0;
211	case IEEE80211_ACTION_CAT_SELF_PROT:
212		if (act >= nitems(meshpl_recv_action))
213			break;
214		meshpl_recv_action[act] = f;
215		return 0;
216	case IEEE80211_ACTION_CAT_MESH:
217		if (act >= nitems(meshaction_recv_action))
218			break;
219		meshaction_recv_action[act] = f;
220		return 0;
221	case IEEE80211_ACTION_CAT_VENDOR:
222		if (act >= nitems(vendor_recv_action))
223			break;
224		vendor_recv_action[act] = f;
225		return 0;
226	case IEEE80211_ACTION_CAT_VHT:
227		if (act >= nitems(vht_recv_action))
228			break;
229		vht_recv_action[act] = f;
230		return 0;
231	}
232	return EINVAL;
233}
234
235void
236ieee80211_recv_action_unregister(int cat, int act)
237{
238	ieee80211_recv_action_register(cat, act, recv_inval);
239}
240
241int
242ieee80211_recv_action(struct ieee80211_node *ni,
243	const struct ieee80211_frame *wh,
244	const uint8_t *frm, const uint8_t *efrm)
245{
246	ieee80211_recv_action_func *f = recv_inval;
247	struct ieee80211vap *vap = ni->ni_vap;
248	const struct ieee80211_action *ia =
249	    (const struct ieee80211_action *) frm;
250
251	switch (ia->ia_category) {
252	case IEEE80211_ACTION_CAT_BA:
253		if (ia->ia_action < nitems(ba_recv_action))
254			f = ba_recv_action[ia->ia_action];
255		break;
256	case IEEE80211_ACTION_CAT_HT:
257		if (ia->ia_action < nitems(ht_recv_action))
258			f = ht_recv_action[ia->ia_action];
259		break;
260	case IEEE80211_ACTION_CAT_SELF_PROT:
261		if (ia->ia_action < nitems(meshpl_recv_action))
262			f = meshpl_recv_action[ia->ia_action];
263		break;
264	case IEEE80211_ACTION_CAT_MESH:
265		if (ni == vap->iv_bss ||
266		    ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) {
267			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH,
268			    ni->ni_macaddr, NULL,
269			    "peer link not yet established (%d), cat %s act %u",
270			    ni->ni_mlstate, "mesh action", ia->ia_action);
271			vap->iv_stats.is_mesh_nolink++;
272			break;
273		}
274		if (ia->ia_action < nitems(meshaction_recv_action))
275			f = meshaction_recv_action[ia->ia_action];
276		break;
277	case IEEE80211_ACTION_CAT_VENDOR:
278		if (ia->ia_action < nitems(vendor_recv_action))
279			f = vendor_recv_action[ia->ia_action];
280		break;
281	case IEEE80211_ACTION_CAT_VHT:
282		if (ia->ia_action < nitems(vht_recv_action))
283			f = vht_recv_action[ia->ia_action];
284		break;
285	}
286	return f(ni, wh, frm, efrm);
287}
288