ieee80211_action.c revision 300232
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: head/sys/net80211/ieee80211_action.c 300232 2016-05-19 21:08:33Z avos $");
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
82int
83ieee80211_send_action_register(int cat, int act, ieee80211_send_action_func *f)
84{
85	switch (cat) {
86	case IEEE80211_ACTION_CAT_BA:
87		if (act >= nitems(ba_send_action))
88			break;
89		ba_send_action[act] = f;
90		return 0;
91	case IEEE80211_ACTION_CAT_HT:
92		if (act >= nitems(ht_send_action))
93			break;
94		ht_send_action[act] = f;
95		return 0;
96	case IEEE80211_ACTION_CAT_SELF_PROT:
97		if (act >= nitems(meshpl_send_action))
98			break;
99		meshpl_send_action[act] = f;
100		return 0;
101	case IEEE80211_ACTION_CAT_MESH:
102		if (act >= nitems(meshaction_send_action))
103			break;
104		meshaction_send_action[act] = f;
105		return 0;
106	case IEEE80211_ACTION_CAT_VENDOR:
107		if (act >= nitems(vendor_send_action))
108			break;
109		vendor_send_action[act] = f;
110		return 0;
111	}
112	return EINVAL;
113}
114
115void
116ieee80211_send_action_unregister(int cat, int act)
117{
118	ieee80211_send_action_register(cat, act, send_inval);
119}
120
121int
122ieee80211_send_action(struct ieee80211_node *ni, int cat, int act, void *sa)
123{
124	ieee80211_send_action_func *f = send_inval;
125
126	switch (cat) {
127	case IEEE80211_ACTION_CAT_BA:
128		if (act < nitems(ba_send_action))
129			f = ba_send_action[act];
130		break;
131	case IEEE80211_ACTION_CAT_HT:
132		if (act < nitems(ht_send_action))
133			f = ht_send_action[act];
134		break;
135	case IEEE80211_ACTION_CAT_SELF_PROT:
136		if (act < nitems(meshpl_send_action))
137			f = meshpl_send_action[act];
138		break;
139	case IEEE80211_ACTION_CAT_MESH:
140		if (act < nitems(meshaction_send_action))
141			f = meshaction_send_action[act];
142		break;
143	case IEEE80211_ACTION_CAT_VENDOR:
144		if (act < nitems(vendor_send_action))
145			f = vendor_send_action[act];
146		break;
147	}
148	return f(ni, cat, act, sa);
149}
150
151static int
152recv_inval(struct ieee80211_node *ni, const struct ieee80211_frame *wh,
153	const uint8_t *frm, const uint8_t *efrm)
154{
155	return EINVAL;
156}
157
158static ieee80211_recv_action_func *ba_recv_action[8] = {
159	recv_inval, recv_inval, recv_inval, recv_inval,
160	recv_inval, recv_inval, recv_inval, recv_inval,
161};
162static ieee80211_recv_action_func *ht_recv_action[8] = {
163	recv_inval, recv_inval, recv_inval, recv_inval,
164	recv_inval, recv_inval, recv_inval, recv_inval,
165};
166static ieee80211_recv_action_func *meshpl_recv_action[8] = {
167	recv_inval, recv_inval, recv_inval, recv_inval,
168	recv_inval, recv_inval, recv_inval, recv_inval,
169};
170static ieee80211_recv_action_func *meshaction_recv_action[12] = {
171	recv_inval, recv_inval, recv_inval, recv_inval,
172	recv_inval, recv_inval, recv_inval, recv_inval,
173	recv_inval, recv_inval, recv_inval, recv_inval,
174};
175static ieee80211_recv_action_func *vendor_recv_action[8] = {
176	recv_inval, recv_inval, recv_inval, recv_inval,
177	recv_inval, recv_inval, recv_inval, recv_inval,
178};
179
180int
181ieee80211_recv_action_register(int cat, int act, ieee80211_recv_action_func *f)
182{
183	switch (cat) {
184	case IEEE80211_ACTION_CAT_BA:
185		if (act >= nitems(ba_recv_action))
186			break;
187		ba_recv_action[act] = f;
188		return 0;
189	case IEEE80211_ACTION_CAT_HT:
190		if (act >= nitems(ht_recv_action))
191			break;
192		ht_recv_action[act] = f;
193		return 0;
194	case IEEE80211_ACTION_CAT_SELF_PROT:
195		if (act >= nitems(meshpl_recv_action))
196			break;
197		meshpl_recv_action[act] = f;
198		return 0;
199	case IEEE80211_ACTION_CAT_MESH:
200		if (act >= nitems(meshaction_recv_action))
201			break;
202		meshaction_recv_action[act] = f;
203		return 0;
204	case IEEE80211_ACTION_CAT_VENDOR:
205		if (act >= nitems(vendor_recv_action))
206			break;
207		vendor_recv_action[act] = f;
208		return 0;
209	}
210	return EINVAL;
211}
212
213void
214ieee80211_recv_action_unregister(int cat, int act)
215{
216	ieee80211_recv_action_register(cat, act, recv_inval);
217}
218
219int
220ieee80211_recv_action(struct ieee80211_node *ni,
221	const struct ieee80211_frame *wh,
222	const uint8_t *frm, const uint8_t *efrm)
223{
224	ieee80211_recv_action_func *f = recv_inval;
225	struct ieee80211vap *vap = ni->ni_vap;
226	const struct ieee80211_action *ia =
227	    (const struct ieee80211_action *) frm;
228
229	switch (ia->ia_category) {
230	case IEEE80211_ACTION_CAT_BA:
231		if (ia->ia_action < nitems(ba_recv_action))
232			f = ba_recv_action[ia->ia_action];
233		break;
234	case IEEE80211_ACTION_CAT_HT:
235		if (ia->ia_action < nitems(ht_recv_action))
236			f = ht_recv_action[ia->ia_action];
237		break;
238	case IEEE80211_ACTION_CAT_SELF_PROT:
239		if (ia->ia_action < nitems(meshpl_recv_action))
240			f = meshpl_recv_action[ia->ia_action];
241		break;
242	case IEEE80211_ACTION_CAT_MESH:
243		if (ni == vap->iv_bss ||
244		    ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) {
245			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH,
246			    ni->ni_macaddr, NULL,
247			    "peer link not yet established (%d), cat %s act %u",
248			    ni->ni_mlstate, "mesh action", ia->ia_action);
249			vap->iv_stats.is_mesh_nolink++;
250			break;
251		}
252		if (ia->ia_action < nitems(meshaction_recv_action))
253			f = meshaction_recv_action[ia->ia_action];
254		break;
255	case IEEE80211_ACTION_CAT_VENDOR:
256		if (ia->ia_action < nitems(vendor_recv_action))
257			f = vendor_recv_action[ia->ia_action];
258		break;
259	}
260	return f(ni, wh, frm, efrm);
261}
262