1195377Ssam/*-
2195377Ssam * Copyright (c) 2009 Sam Leffler, Errno Consulting
3195377Ssam * All rights reserved.
4195377Ssam *
5195377Ssam * Redistribution and use in source and binary forms, with or without
6195377Ssam * modification, are permitted provided that the following conditions
7195377Ssam * are met:
8195377Ssam * 1. Redistributions of source code must retain the above copyright
9195377Ssam *    notice, this list of conditions and the following disclaimer.
10195377Ssam * 2. Redistributions in binary form must reproduce the above copyright
11195377Ssam *    notice, this list of conditions and the following disclaimer in the
12195377Ssam *    documentation and/or other materials provided with the distribution.
13195377Ssam *
14195377Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15195377Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16195377Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17195377Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18195377Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19195377Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20195377Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21195377Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22195377Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23195377Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24195377Ssam */
25195377Ssam
26195377Ssam#include <sys/cdefs.h>
27195377Ssam#ifdef __FreeBSD__
28195377Ssam__FBSDID("$FreeBSD$");
29195377Ssam#endif
30195377Ssam
31195377Ssam/*
32195377Ssam * IEEE 802.11 send/recv action frame support.
33195377Ssam */
34195377Ssam
35195377Ssam#include "opt_inet.h"
36195377Ssam#include "opt_wlan.h"
37195377Ssam
38195377Ssam#include <sys/param.h>
39195377Ssam#include <sys/kernel.h>
40195377Ssam#include <sys/systm.h>
41195377Ssam
42195377Ssam#include <sys/socket.h>
43195377Ssam
44195377Ssam#include <net/if.h>
45195377Ssam#include <net/if_media.h>
46195377Ssam#include <net/ethernet.h>
47195377Ssam
48195377Ssam#include <net80211/ieee80211_var.h>
49195377Ssam#include <net80211/ieee80211_action.h>
50195618Srpaulo#include <net80211/ieee80211_mesh.h>
51195377Ssam
52195377Ssamstatic int
53195377Ssamsend_inval(struct ieee80211_node *ni, int cat, int act, void *sa)
54195377Ssam{
55195377Ssam	return EINVAL;
56195377Ssam}
57195377Ssam
58195377Ssamstatic ieee80211_send_action_func *ba_send_action[8] = {
59195377Ssam	send_inval, send_inval, send_inval, send_inval,
60195377Ssam	send_inval, send_inval, send_inval, send_inval,
61195377Ssam};
62195377Ssamstatic ieee80211_send_action_func *ht_send_action[8] = {
63195377Ssam	send_inval, send_inval, send_inval, send_inval,
64195377Ssam	send_inval, send_inval, send_inval, send_inval,
65195377Ssam};
66195377Ssamstatic ieee80211_send_action_func *meshpl_send_action[8] = {
67195377Ssam	send_inval, send_inval, send_inval, send_inval,
68195377Ssam	send_inval, send_inval, send_inval, send_inval,
69195377Ssam};
70246502Smonthadarstatic ieee80211_send_action_func *meshaction_send_action[12] = {
71195377Ssam	send_inval, send_inval, send_inval, send_inval,
72195377Ssam	send_inval, send_inval, send_inval, send_inval,
73195377Ssam	send_inval, send_inval, send_inval, send_inval,
74195377Ssam};
75195377Ssamstatic ieee80211_send_action_func *vendor_send_action[8] = {
76195377Ssam	send_inval, send_inval, send_inval, send_inval,
77195377Ssam	send_inval, send_inval, send_inval, send_inval,
78195377Ssam};
79195377Ssam
80195377Ssamint
81195377Ssamieee80211_send_action_register(int cat, int act, ieee80211_send_action_func *f)
82195377Ssam{
83195377Ssam	switch (cat) {
84195377Ssam	case IEEE80211_ACTION_CAT_BA:
85254315Srpaulo		if (act >= nitems(ba_send_action))
86195377Ssam			break;
87195377Ssam		ba_send_action[act] = f;
88195377Ssam		return 0;
89195377Ssam	case IEEE80211_ACTION_CAT_HT:
90254315Srpaulo		if (act >= nitems(ht_send_action))
91195377Ssam			break;
92195377Ssam		ht_send_action[act] = f;
93195377Ssam		return 0;
94234874Smonthadar	case IEEE80211_ACTION_CAT_SELF_PROT:
95254315Srpaulo		if (act >= nitems(meshpl_send_action))
96195377Ssam			break;
97195377Ssam		meshpl_send_action[act] = f;
98195377Ssam		return 0;
99232479Sadrian	case IEEE80211_ACTION_CAT_MESH:
100254315Srpaulo		if (act >= nitems(meshaction_send_action))
101246502Smonthadar			break;
102246502Smonthadar		meshaction_send_action[act] = f;
103246502Smonthadar		return 0;
104232479Sadrian		break;
105195377Ssam	case IEEE80211_ACTION_CAT_VENDOR:
106254315Srpaulo		if (act >= nitems(vendor_send_action))
107195377Ssam			break;
108195377Ssam		vendor_send_action[act] = f;
109195377Ssam		return 0;
110195377Ssam	}
111195377Ssam	return EINVAL;
112195377Ssam}
113195377Ssam
114195377Ssamvoid
115195377Ssamieee80211_send_action_unregister(int cat, int act)
116195377Ssam{
117195377Ssam	ieee80211_send_action_register(cat, act, send_inval);
118195377Ssam}
119195377Ssam
120195377Ssamint
121195377Ssamieee80211_send_action(struct ieee80211_node *ni, int cat, int act, void *sa)
122195377Ssam{
123195377Ssam	ieee80211_send_action_func *f = send_inval;
124195377Ssam
125195377Ssam	switch (cat) {
126195377Ssam	case IEEE80211_ACTION_CAT_BA:
127254315Srpaulo		if (act < nitems(ba_send_action))
128195377Ssam			f = ba_send_action[act];
129195377Ssam		break;
130195377Ssam	case IEEE80211_ACTION_CAT_HT:
131254315Srpaulo		if (act < nitems(ht_send_action))
132195377Ssam			f = ht_send_action[act];
133195377Ssam		break;
134234874Smonthadar	case IEEE80211_ACTION_CAT_SELF_PROT:
135254315Srpaulo		if (act < nitems(meshpl_send_action))
136195377Ssam			f = meshpl_send_action[act];
137195377Ssam		break;
138232479Sadrian	case IEEE80211_ACTION_CAT_MESH:
139254315Srpaulo		if (act < nitems(meshaction_send_action))
140246502Smonthadar			f = meshaction_send_action[act];
141195377Ssam		break;
142195377Ssam	case IEEE80211_ACTION_CAT_VENDOR:
143254315Srpaulo		if (act < nitems(vendor_send_action))
144195377Ssam			f = vendor_send_action[act];
145195377Ssam		break;
146195377Ssam	}
147195377Ssam	return f(ni, cat, act, sa);
148195377Ssam}
149195377Ssam
150195377Ssamstatic int
151195377Ssamrecv_inval(struct ieee80211_node *ni, const struct ieee80211_frame *wh,
152195377Ssam	const uint8_t *frm, const uint8_t *efrm)
153195377Ssam{
154195377Ssam	return EINVAL;
155195377Ssam}
156195377Ssam
157195377Ssamstatic ieee80211_recv_action_func *ba_recv_action[8] = {
158195377Ssam	recv_inval, recv_inval, recv_inval, recv_inval,
159195377Ssam	recv_inval, recv_inval, recv_inval, recv_inval,
160195377Ssam};
161195377Ssamstatic ieee80211_recv_action_func *ht_recv_action[8] = {
162195377Ssam	recv_inval, recv_inval, recv_inval, recv_inval,
163195377Ssam	recv_inval, recv_inval, recv_inval, recv_inval,
164195377Ssam};
165195377Ssamstatic ieee80211_recv_action_func *meshpl_recv_action[8] = {
166195377Ssam	recv_inval, recv_inval, recv_inval, recv_inval,
167195377Ssam	recv_inval, recv_inval, recv_inval, recv_inval,
168195377Ssam};
169246502Smonthadarstatic ieee80211_recv_action_func *meshaction_recv_action[12] = {
170195377Ssam	recv_inval, recv_inval, recv_inval, recv_inval,
171195377Ssam	recv_inval, recv_inval, recv_inval, recv_inval,
172195377Ssam	recv_inval, recv_inval, recv_inval, recv_inval,
173195377Ssam};
174195377Ssamstatic ieee80211_recv_action_func *vendor_recv_action[8] = {
175195377Ssam	recv_inval, recv_inval, recv_inval, recv_inval,
176195377Ssam	recv_inval, recv_inval, recv_inval, recv_inval,
177195377Ssam};
178195377Ssam
179195377Ssamint
180195377Ssamieee80211_recv_action_register(int cat, int act, ieee80211_recv_action_func *f)
181195377Ssam{
182195377Ssam	switch (cat) {
183195377Ssam	case IEEE80211_ACTION_CAT_BA:
184254315Srpaulo		if (act >= nitems(ba_recv_action))
185195377Ssam			break;
186195377Ssam		ba_recv_action[act] = f;
187195377Ssam		return 0;
188195377Ssam	case IEEE80211_ACTION_CAT_HT:
189254315Srpaulo		if (act >= nitems(ht_recv_action))
190195377Ssam			break;
191195377Ssam		ht_recv_action[act] = f;
192195377Ssam		return 0;
193234874Smonthadar	case IEEE80211_ACTION_CAT_SELF_PROT:
194254315Srpaulo		if (act >= nitems(meshpl_recv_action))
195195377Ssam			break;
196195377Ssam		meshpl_recv_action[act] = f;
197195377Ssam		return 0;
198232479Sadrian	case IEEE80211_ACTION_CAT_MESH:
199254315Srpaulo		if (act >= nitems(meshaction_recv_action))
200246502Smonthadar			break;
201246502Smonthadar		meshaction_recv_action[act] = f;
202246502Smonthadar		return 0;
203195377Ssam	case IEEE80211_ACTION_CAT_VENDOR:
204254315Srpaulo		if (act >= nitems(vendor_recv_action))
205195377Ssam			break;
206195377Ssam		vendor_recv_action[act] = f;
207195377Ssam		return 0;
208195377Ssam	}
209195377Ssam	return EINVAL;
210195377Ssam}
211195377Ssam
212195377Ssamvoid
213195377Ssamieee80211_recv_action_unregister(int cat, int act)
214195377Ssam{
215195377Ssam	ieee80211_recv_action_register(cat, act, recv_inval);
216195377Ssam}
217195377Ssam
218195377Ssamint
219195377Ssamieee80211_recv_action(struct ieee80211_node *ni,
220195377Ssam	const struct ieee80211_frame *wh,
221195377Ssam	const uint8_t *frm, const uint8_t *efrm)
222195377Ssam{
223195377Ssam	ieee80211_recv_action_func *f = recv_inval;
224246503Smonthadar	struct ieee80211vap *vap = ni->ni_vap;
225195377Ssam	const struct ieee80211_action *ia =
226195377Ssam	    (const struct ieee80211_action *) frm;
227195377Ssam
228195377Ssam	switch (ia->ia_category) {
229195377Ssam	case IEEE80211_ACTION_CAT_BA:
230254315Srpaulo		if (ia->ia_action < nitems(ba_recv_action))
231195377Ssam			f = ba_recv_action[ia->ia_action];
232195377Ssam		break;
233195377Ssam	case IEEE80211_ACTION_CAT_HT:
234254315Srpaulo		if (ia->ia_action < nitems(ht_recv_action))
235195377Ssam			f = ht_recv_action[ia->ia_action];
236195377Ssam		break;
237234874Smonthadar	case IEEE80211_ACTION_CAT_SELF_PROT:
238254315Srpaulo		if (ia->ia_action < nitems(meshpl_recv_action))
239195377Ssam			f = meshpl_recv_action[ia->ia_action];
240195377Ssam		break;
241232479Sadrian	case IEEE80211_ACTION_CAT_MESH:
242246503Smonthadar		if (ni == vap->iv_bss ||
243246503Smonthadar		    ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) {
244246503Smonthadar			IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH,
245246503Smonthadar			    ni->ni_macaddr, NULL,
246246503Smonthadar			    "peer link not yet established (%d), cat %s act %u",
247246503Smonthadar			    ni->ni_mlstate, "mesh action", ia->ia_action);
248246503Smonthadar			vap->iv_stats.is_mesh_nolink++;
249246503Smonthadar			break;
250246503Smonthadar		}
251254315Srpaulo		if (ia->ia_action < nitems(meshaction_recv_action))
252246502Smonthadar			f = meshaction_recv_action[ia->ia_action];
253195377Ssam		break;
254195377Ssam	case IEEE80211_ACTION_CAT_VENDOR:
255254315Srpaulo		if (ia->ia_action < nitems(vendor_recv_action))
256195377Ssam			f = vendor_recv_action[ia->ia_action];
257195377Ssam		break;
258195377Ssam	}
259195377Ssam	return f(ni, wh, frm, efrm);
260195377Ssam}
261