132176cfdSRui Paulo /*-
232176cfdSRui Paulo * Copyright (c) 2009 Sam Leffler, Errno Consulting
332176cfdSRui Paulo * All rights reserved.
432176cfdSRui Paulo *
532176cfdSRui Paulo * Redistribution and use in source and binary forms, with or without
632176cfdSRui Paulo * modification, are permitted provided that the following conditions
732176cfdSRui Paulo * are met:
832176cfdSRui Paulo * 1. Redistributions of source code must retain the above copyright
932176cfdSRui Paulo * notice, this list of conditions and the following disclaimer.
1032176cfdSRui Paulo * 2. Redistributions in binary form must reproduce the above copyright
1132176cfdSRui Paulo * notice, this list of conditions and the following disclaimer in the
1232176cfdSRui Paulo * documentation and/or other materials provided with the distribution.
1332176cfdSRui Paulo *
1432176cfdSRui Paulo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1532176cfdSRui Paulo * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1632176cfdSRui Paulo * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1732176cfdSRui Paulo * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1832176cfdSRui Paulo * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1932176cfdSRui Paulo * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2032176cfdSRui Paulo * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2132176cfdSRui Paulo * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2232176cfdSRui Paulo * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2332176cfdSRui Paulo * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2432176cfdSRui Paulo */
2532176cfdSRui Paulo
26085ff963SMatthew Dillon #include <sys/cdefs.h>
27085ff963SMatthew Dillon #ifdef __FreeBSD__
28085ff963SMatthew Dillon __FBSDID("$FreeBSD$");
29085ff963SMatthew Dillon #endif
30085ff963SMatthew Dillon
3132176cfdSRui Paulo /*
3232176cfdSRui Paulo * IEEE 802.11 send/recv action frame support.
3332176cfdSRui Paulo */
3432176cfdSRui Paulo
3532176cfdSRui Paulo #include "opt_inet.h"
3632176cfdSRui Paulo #include "opt_wlan.h"
3732176cfdSRui Paulo
3832176cfdSRui Paulo #include <sys/param.h>
3932176cfdSRui Paulo #include <sys/kernel.h>
40*4f655ef5SMatthew Dillon #include <sys/malloc.h>
4132176cfdSRui Paulo #include <sys/systm.h>
4232176cfdSRui Paulo
4332176cfdSRui Paulo #include <sys/socket.h>
4432176cfdSRui Paulo
4532176cfdSRui Paulo #include <net/if.h>
46085ff963SMatthew Dillon #include <net/if_var.h>
4732176cfdSRui Paulo #include <net/if_media.h>
4832176cfdSRui Paulo #include <net/ethernet.h>
4932176cfdSRui Paulo
5032176cfdSRui Paulo #include <netproto/802_11/ieee80211_var.h>
5132176cfdSRui Paulo #include <netproto/802_11/ieee80211_action.h>
5232176cfdSRui Paulo #include <netproto/802_11/ieee80211_mesh.h>
5332176cfdSRui Paulo
5432176cfdSRui Paulo static int
send_inval(struct ieee80211_node * ni,int cat,int act,void * sa)5532176cfdSRui Paulo send_inval(struct ieee80211_node *ni, int cat, int act, void *sa)
5632176cfdSRui Paulo {
5732176cfdSRui Paulo return EINVAL;
5832176cfdSRui Paulo }
5932176cfdSRui Paulo
6032176cfdSRui Paulo static ieee80211_send_action_func *ba_send_action[8] = {
6132176cfdSRui Paulo send_inval, send_inval, send_inval, send_inval,
6232176cfdSRui Paulo send_inval, send_inval, send_inval, send_inval,
6332176cfdSRui Paulo };
6432176cfdSRui Paulo static ieee80211_send_action_func *ht_send_action[8] = {
6532176cfdSRui Paulo send_inval, send_inval, send_inval, send_inval,
6632176cfdSRui Paulo send_inval, send_inval, send_inval, send_inval,
6732176cfdSRui Paulo };
6832176cfdSRui Paulo static ieee80211_send_action_func *meshpl_send_action[8] = {
6932176cfdSRui Paulo send_inval, send_inval, send_inval, send_inval,
7032176cfdSRui Paulo send_inval, send_inval, send_inval, send_inval,
7132176cfdSRui Paulo };
72085ff963SMatthew Dillon static ieee80211_send_action_func *meshaction_send_action[12] = {
7332176cfdSRui Paulo send_inval, send_inval, send_inval, send_inval,
7432176cfdSRui Paulo send_inval, send_inval, send_inval, send_inval,
7532176cfdSRui Paulo send_inval, send_inval, send_inval, send_inval,
7632176cfdSRui Paulo };
7732176cfdSRui Paulo static ieee80211_send_action_func *vendor_send_action[8] = {
7832176cfdSRui Paulo send_inval, send_inval, send_inval, send_inval,
7932176cfdSRui Paulo send_inval, send_inval, send_inval, send_inval,
8032176cfdSRui Paulo };
8132176cfdSRui Paulo
8232176cfdSRui Paulo int
ieee80211_send_action_register(int cat,int act,ieee80211_send_action_func * f)8332176cfdSRui Paulo ieee80211_send_action_register(int cat, int act, ieee80211_send_action_func *f)
8432176cfdSRui Paulo {
8532176cfdSRui Paulo switch (cat) {
8632176cfdSRui Paulo case IEEE80211_ACTION_CAT_BA:
87085ff963SMatthew Dillon if (act >= nitems(ba_send_action))
8832176cfdSRui Paulo break;
8932176cfdSRui Paulo ba_send_action[act] = f;
9032176cfdSRui Paulo return 0;
9132176cfdSRui Paulo case IEEE80211_ACTION_CAT_HT:
92085ff963SMatthew Dillon if (act >= nitems(ht_send_action))
9332176cfdSRui Paulo break;
9432176cfdSRui Paulo ht_send_action[act] = f;
9532176cfdSRui Paulo return 0;
96085ff963SMatthew Dillon case IEEE80211_ACTION_CAT_SELF_PROT:
97085ff963SMatthew Dillon if (act >= nitems(meshpl_send_action))
9832176cfdSRui Paulo break;
9932176cfdSRui Paulo meshpl_send_action[act] = f;
10032176cfdSRui Paulo return 0;
101085ff963SMatthew Dillon case IEEE80211_ACTION_CAT_MESH:
102085ff963SMatthew Dillon if (act >= nitems(meshaction_send_action))
10332176cfdSRui Paulo break;
104085ff963SMatthew Dillon meshaction_send_action[act] = f;
10532176cfdSRui Paulo return 0;
10632176cfdSRui Paulo break;
10732176cfdSRui Paulo case IEEE80211_ACTION_CAT_VENDOR:
108085ff963SMatthew Dillon if (act >= nitems(vendor_send_action))
10932176cfdSRui Paulo break;
11032176cfdSRui Paulo vendor_send_action[act] = f;
11132176cfdSRui Paulo return 0;
11232176cfdSRui Paulo }
11332176cfdSRui Paulo return EINVAL;
11432176cfdSRui Paulo }
11532176cfdSRui Paulo
11632176cfdSRui Paulo void
ieee80211_send_action_unregister(int cat,int act)11732176cfdSRui Paulo ieee80211_send_action_unregister(int cat, int act)
11832176cfdSRui Paulo {
11932176cfdSRui Paulo ieee80211_send_action_register(cat, act, send_inval);
12032176cfdSRui Paulo }
12132176cfdSRui Paulo
12232176cfdSRui Paulo int
ieee80211_send_action(struct ieee80211_node * ni,int cat,int act,void * sa)12332176cfdSRui Paulo ieee80211_send_action(struct ieee80211_node *ni, int cat, int act, void *sa)
12432176cfdSRui Paulo {
12532176cfdSRui Paulo ieee80211_send_action_func *f = send_inval;
12632176cfdSRui Paulo
12732176cfdSRui Paulo switch (cat) {
12832176cfdSRui Paulo case IEEE80211_ACTION_CAT_BA:
129085ff963SMatthew Dillon if (act < nitems(ba_send_action))
13032176cfdSRui Paulo f = ba_send_action[act];
13132176cfdSRui Paulo break;
13232176cfdSRui Paulo case IEEE80211_ACTION_CAT_HT:
133085ff963SMatthew Dillon if (act < nitems(ht_send_action))
13432176cfdSRui Paulo f = ht_send_action[act];
13532176cfdSRui Paulo break;
136085ff963SMatthew Dillon case IEEE80211_ACTION_CAT_SELF_PROT:
137085ff963SMatthew Dillon if (act < nitems(meshpl_send_action))
13832176cfdSRui Paulo f = meshpl_send_action[act];
13932176cfdSRui Paulo break;
140085ff963SMatthew Dillon case IEEE80211_ACTION_CAT_MESH:
141085ff963SMatthew Dillon if (act < nitems(meshaction_send_action))
142085ff963SMatthew Dillon f = meshaction_send_action[act];
14332176cfdSRui Paulo break;
14432176cfdSRui Paulo case IEEE80211_ACTION_CAT_VENDOR:
145085ff963SMatthew Dillon if (act < nitems(vendor_send_action))
14632176cfdSRui Paulo f = vendor_send_action[act];
14732176cfdSRui Paulo break;
14832176cfdSRui Paulo }
14932176cfdSRui Paulo return f(ni, cat, act, sa);
15032176cfdSRui Paulo }
15132176cfdSRui Paulo
15232176cfdSRui Paulo static int
recv_inval(struct ieee80211_node * ni,const struct ieee80211_frame * wh,const uint8_t * frm,const uint8_t * efrm)15332176cfdSRui Paulo recv_inval(struct ieee80211_node *ni, const struct ieee80211_frame *wh,
15432176cfdSRui Paulo const uint8_t *frm, const uint8_t *efrm)
15532176cfdSRui Paulo {
15632176cfdSRui Paulo return EINVAL;
15732176cfdSRui Paulo }
15832176cfdSRui Paulo
15932176cfdSRui Paulo static ieee80211_recv_action_func *ba_recv_action[8] = {
16032176cfdSRui Paulo recv_inval, recv_inval, recv_inval, recv_inval,
16132176cfdSRui Paulo recv_inval, recv_inval, recv_inval, recv_inval,
16232176cfdSRui Paulo };
16332176cfdSRui Paulo static ieee80211_recv_action_func *ht_recv_action[8] = {
16432176cfdSRui Paulo recv_inval, recv_inval, recv_inval, recv_inval,
16532176cfdSRui Paulo recv_inval, recv_inval, recv_inval, recv_inval,
16632176cfdSRui Paulo };
16732176cfdSRui Paulo static ieee80211_recv_action_func *meshpl_recv_action[8] = {
16832176cfdSRui Paulo recv_inval, recv_inval, recv_inval, recv_inval,
16932176cfdSRui Paulo recv_inval, recv_inval, recv_inval, recv_inval,
17032176cfdSRui Paulo };
171085ff963SMatthew Dillon static ieee80211_recv_action_func *meshaction_recv_action[12] = {
17232176cfdSRui Paulo recv_inval, recv_inval, recv_inval, recv_inval,
17332176cfdSRui Paulo recv_inval, recv_inval, recv_inval, recv_inval,
17432176cfdSRui Paulo recv_inval, recv_inval, recv_inval, recv_inval,
17532176cfdSRui Paulo };
17632176cfdSRui Paulo static ieee80211_recv_action_func *vendor_recv_action[8] = {
17732176cfdSRui Paulo recv_inval, recv_inval, recv_inval, recv_inval,
17832176cfdSRui Paulo recv_inval, recv_inval, recv_inval, recv_inval,
17932176cfdSRui Paulo };
18032176cfdSRui Paulo
18132176cfdSRui Paulo int
ieee80211_recv_action_register(int cat,int act,ieee80211_recv_action_func * f)18232176cfdSRui Paulo ieee80211_recv_action_register(int cat, int act, ieee80211_recv_action_func *f)
18332176cfdSRui Paulo {
18432176cfdSRui Paulo switch (cat) {
18532176cfdSRui Paulo case IEEE80211_ACTION_CAT_BA:
186085ff963SMatthew Dillon if (act >= nitems(ba_recv_action))
18732176cfdSRui Paulo break;
18832176cfdSRui Paulo ba_recv_action[act] = f;
18932176cfdSRui Paulo return 0;
19032176cfdSRui Paulo case IEEE80211_ACTION_CAT_HT:
191085ff963SMatthew Dillon if (act >= nitems(ht_recv_action))
19232176cfdSRui Paulo break;
19332176cfdSRui Paulo ht_recv_action[act] = f;
19432176cfdSRui Paulo return 0;
195085ff963SMatthew Dillon case IEEE80211_ACTION_CAT_SELF_PROT:
196085ff963SMatthew Dillon if (act >= nitems(meshpl_recv_action))
19732176cfdSRui Paulo break;
19832176cfdSRui Paulo meshpl_recv_action[act] = f;
19932176cfdSRui Paulo return 0;
200085ff963SMatthew Dillon case IEEE80211_ACTION_CAT_MESH:
201085ff963SMatthew Dillon if (act >= nitems(meshaction_recv_action))
20232176cfdSRui Paulo break;
203085ff963SMatthew Dillon meshaction_recv_action[act] = f;
20432176cfdSRui Paulo return 0;
20532176cfdSRui Paulo case IEEE80211_ACTION_CAT_VENDOR:
206085ff963SMatthew Dillon if (act >= nitems(vendor_recv_action))
20732176cfdSRui Paulo break;
20832176cfdSRui Paulo vendor_recv_action[act] = f;
20932176cfdSRui Paulo return 0;
21032176cfdSRui Paulo }
21132176cfdSRui Paulo return EINVAL;
21232176cfdSRui Paulo }
21332176cfdSRui Paulo
21432176cfdSRui Paulo void
ieee80211_recv_action_unregister(int cat,int act)21532176cfdSRui Paulo ieee80211_recv_action_unregister(int cat, int act)
21632176cfdSRui Paulo {
21732176cfdSRui Paulo ieee80211_recv_action_register(cat, act, recv_inval);
21832176cfdSRui Paulo }
21932176cfdSRui Paulo
22032176cfdSRui Paulo int
ieee80211_recv_action(struct ieee80211_node * ni,const struct ieee80211_frame * wh,const uint8_t * frm,const uint8_t * efrm)22132176cfdSRui Paulo ieee80211_recv_action(struct ieee80211_node *ni,
22232176cfdSRui Paulo const struct ieee80211_frame *wh,
22332176cfdSRui Paulo const uint8_t *frm, const uint8_t *efrm)
22432176cfdSRui Paulo {
22532176cfdSRui Paulo ieee80211_recv_action_func *f = recv_inval;
226085ff963SMatthew Dillon struct ieee80211vap *vap = ni->ni_vap;
22732176cfdSRui Paulo const struct ieee80211_action *ia =
22832176cfdSRui Paulo (const struct ieee80211_action *) frm;
22932176cfdSRui Paulo
23032176cfdSRui Paulo switch (ia->ia_category) {
23132176cfdSRui Paulo case IEEE80211_ACTION_CAT_BA:
232085ff963SMatthew Dillon if (ia->ia_action < nitems(ba_recv_action))
23332176cfdSRui Paulo f = ba_recv_action[ia->ia_action];
23432176cfdSRui Paulo break;
23532176cfdSRui Paulo case IEEE80211_ACTION_CAT_HT:
236085ff963SMatthew Dillon if (ia->ia_action < nitems(ht_recv_action))
23732176cfdSRui Paulo f = ht_recv_action[ia->ia_action];
23832176cfdSRui Paulo break;
239085ff963SMatthew Dillon case IEEE80211_ACTION_CAT_SELF_PROT:
240085ff963SMatthew Dillon if (ia->ia_action < nitems(meshpl_recv_action))
24132176cfdSRui Paulo f = meshpl_recv_action[ia->ia_action];
24232176cfdSRui Paulo break;
243085ff963SMatthew Dillon case IEEE80211_ACTION_CAT_MESH:
244085ff963SMatthew Dillon if (ni == vap->iv_bss ||
245085ff963SMatthew Dillon ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) {
246085ff963SMatthew Dillon IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH,
247085ff963SMatthew Dillon ni->ni_macaddr, NULL,
248085ff963SMatthew Dillon "peer link not yet established (%d), cat %s act %u",
249085ff963SMatthew Dillon ni->ni_mlstate, "mesh action", ia->ia_action);
250085ff963SMatthew Dillon vap->iv_stats.is_mesh_nolink++;
25132176cfdSRui Paulo break;
252085ff963SMatthew Dillon }
253085ff963SMatthew Dillon if (ia->ia_action < nitems(meshaction_recv_action))
254085ff963SMatthew Dillon f = meshaction_recv_action[ia->ia_action];
25532176cfdSRui Paulo break;
25632176cfdSRui Paulo case IEEE80211_ACTION_CAT_VENDOR:
257085ff963SMatthew Dillon if (ia->ia_action < nitems(vendor_recv_action))
25832176cfdSRui Paulo f = vendor_recv_action[ia->ia_action];
25932176cfdSRui Paulo break;
26032176cfdSRui Paulo }
26132176cfdSRui Paulo return f(ni, wh, frm, efrm);
26232176cfdSRui Paulo }
263