176340123SSam Leffler /*- 276340123SSam Leffler * Copyright (c) 2009 Sam Leffler, Errno Consulting 376340123SSam Leffler * All rights reserved. 476340123SSam Leffler * 576340123SSam Leffler * Redistribution and use in source and binary forms, with or without 676340123SSam Leffler * modification, are permitted provided that the following conditions 776340123SSam Leffler * are met: 876340123SSam Leffler * 1. Redistributions of source code must retain the above copyright 976340123SSam Leffler * notice, this list of conditions and the following disclaimer. 1076340123SSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 1176340123SSam Leffler * notice, this list of conditions and the following disclaimer in the 1276340123SSam Leffler * documentation and/or other materials provided with the distribution. 1376340123SSam Leffler * 1476340123SSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1576340123SSam Leffler * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1676340123SSam Leffler * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1776340123SSam Leffler * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1876340123SSam Leffler * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1976340123SSam Leffler * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2076340123SSam Leffler * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2176340123SSam Leffler * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2276340123SSam Leffler * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2376340123SSam Leffler * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2476340123SSam Leffler */ 2576340123SSam Leffler 2676340123SSam Leffler #include <sys/cdefs.h> 2776340123SSam Leffler #ifdef __FreeBSD__ 2876340123SSam Leffler __FBSDID("$FreeBSD$"); 2976340123SSam Leffler #endif 3076340123SSam Leffler 3176340123SSam Leffler /* 3276340123SSam Leffler * IEEE 802.11 send/recv action frame support. 3376340123SSam Leffler */ 3476340123SSam Leffler 3576340123SSam Leffler #include "opt_inet.h" 3676340123SSam Leffler #include "opt_wlan.h" 3776340123SSam Leffler 3876340123SSam Leffler #include <sys/param.h> 3976340123SSam Leffler #include <sys/kernel.h> 4076340123SSam Leffler #include <sys/systm.h> 4176340123SSam Leffler 4276340123SSam Leffler #include <sys/socket.h> 4376340123SSam Leffler 4476340123SSam Leffler #include <net/if.h> 4576340123SSam Leffler #include <net/if_media.h> 4676340123SSam Leffler #include <net/ethernet.h> 4776340123SSam Leffler 4876340123SSam Leffler #include <net80211/ieee80211_var.h> 4976340123SSam Leffler #include <net80211/ieee80211_action.h> 5059aa14a9SRui Paulo #include <net80211/ieee80211_mesh.h> 5176340123SSam Leffler 5276340123SSam Leffler static int 5376340123SSam Leffler send_inval(struct ieee80211_node *ni, int cat, int act, void *sa) 5476340123SSam Leffler { 5576340123SSam Leffler return EINVAL; 5676340123SSam Leffler } 5776340123SSam Leffler 5876340123SSam Leffler static ieee80211_send_action_func *ba_send_action[8] = { 5976340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 6076340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 6176340123SSam Leffler }; 6276340123SSam Leffler static ieee80211_send_action_func *ht_send_action[8] = { 6376340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 6476340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 6576340123SSam Leffler }; 6676340123SSam Leffler static ieee80211_send_action_func *meshpl_send_action[8] = { 6776340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 6876340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 6976340123SSam Leffler }; 7071766338SMonthadar Al Jaberi static ieee80211_send_action_func *meshaction_send_action[12] = { 7176340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 7276340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 7376340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 7476340123SSam Leffler }; 7576340123SSam Leffler static ieee80211_send_action_func *vendor_send_action[8] = { 7676340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 7776340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 7876340123SSam Leffler }; 7976340123SSam Leffler 8076340123SSam Leffler int 8176340123SSam Leffler ieee80211_send_action_register(int cat, int act, ieee80211_send_action_func *f) 8276340123SSam Leffler { 8376340123SSam Leffler switch (cat) { 8476340123SSam Leffler case IEEE80211_ACTION_CAT_BA: 85*a3e08d6fSRui Paulo if (act >= nitems(ba_send_action)) 8676340123SSam Leffler break; 8776340123SSam Leffler ba_send_action[act] = f; 8876340123SSam Leffler return 0; 8976340123SSam Leffler case IEEE80211_ACTION_CAT_HT: 90*a3e08d6fSRui Paulo if (act >= nitems(ht_send_action)) 9176340123SSam Leffler break; 9276340123SSam Leffler ht_send_action[act] = f; 9376340123SSam Leffler return 0; 94ebeaa1adSMonthadar Al Jaberi case IEEE80211_ACTION_CAT_SELF_PROT: 95*a3e08d6fSRui Paulo if (act >= nitems(meshpl_send_action)) 9676340123SSam Leffler break; 9776340123SSam Leffler meshpl_send_action[act] = f; 9876340123SSam Leffler return 0; 99bdd2a076SAdrian Chadd case IEEE80211_ACTION_CAT_MESH: 100*a3e08d6fSRui Paulo if (act >= nitems(meshaction_send_action)) 10176340123SSam Leffler break; 10271766338SMonthadar Al Jaberi meshaction_send_action[act] = f; 10376340123SSam Leffler return 0; 104bdd2a076SAdrian Chadd break; 10576340123SSam Leffler case IEEE80211_ACTION_CAT_VENDOR: 106*a3e08d6fSRui Paulo if (act >= nitems(vendor_send_action)) 10776340123SSam Leffler break; 10876340123SSam Leffler vendor_send_action[act] = f; 10976340123SSam Leffler return 0; 11076340123SSam Leffler } 11176340123SSam Leffler return EINVAL; 11276340123SSam Leffler } 11376340123SSam Leffler 11476340123SSam Leffler void 11576340123SSam Leffler ieee80211_send_action_unregister(int cat, int act) 11676340123SSam Leffler { 11776340123SSam Leffler ieee80211_send_action_register(cat, act, send_inval); 11876340123SSam Leffler } 11976340123SSam Leffler 12076340123SSam Leffler int 12176340123SSam Leffler ieee80211_send_action(struct ieee80211_node *ni, int cat, int act, void *sa) 12276340123SSam Leffler { 12376340123SSam Leffler ieee80211_send_action_func *f = send_inval; 12476340123SSam Leffler 12576340123SSam Leffler switch (cat) { 12676340123SSam Leffler case IEEE80211_ACTION_CAT_BA: 127*a3e08d6fSRui Paulo if (act < nitems(ba_send_action)) 12876340123SSam Leffler f = ba_send_action[act]; 12976340123SSam Leffler break; 13076340123SSam Leffler case IEEE80211_ACTION_CAT_HT: 131*a3e08d6fSRui Paulo if (act < nitems(ht_send_action)) 13276340123SSam Leffler f = ht_send_action[act]; 13376340123SSam Leffler break; 134ebeaa1adSMonthadar Al Jaberi case IEEE80211_ACTION_CAT_SELF_PROT: 135*a3e08d6fSRui Paulo if (act < nitems(meshpl_send_action)) 13676340123SSam Leffler f = meshpl_send_action[act]; 13776340123SSam Leffler break; 138bdd2a076SAdrian Chadd case IEEE80211_ACTION_CAT_MESH: 139*a3e08d6fSRui Paulo if (act < nitems(meshaction_send_action)) 14071766338SMonthadar Al Jaberi f = meshaction_send_action[act]; 141bdd2a076SAdrian Chadd break; 14276340123SSam Leffler case IEEE80211_ACTION_CAT_VENDOR: 143*a3e08d6fSRui Paulo if (act < nitems(vendor_send_action)) 14476340123SSam Leffler f = vendor_send_action[act]; 14576340123SSam Leffler break; 14676340123SSam Leffler } 14776340123SSam Leffler return f(ni, cat, act, sa); 14876340123SSam Leffler } 14976340123SSam Leffler 15076340123SSam Leffler static int 15176340123SSam Leffler recv_inval(struct ieee80211_node *ni, const struct ieee80211_frame *wh, 15276340123SSam Leffler const uint8_t *frm, const uint8_t *efrm) 15376340123SSam Leffler { 15476340123SSam Leffler return EINVAL; 15576340123SSam Leffler } 15676340123SSam Leffler 15776340123SSam Leffler static ieee80211_recv_action_func *ba_recv_action[8] = { 15876340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 15976340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 16076340123SSam Leffler }; 16176340123SSam Leffler static ieee80211_recv_action_func *ht_recv_action[8] = { 16276340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 16376340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 16476340123SSam Leffler }; 16576340123SSam Leffler static ieee80211_recv_action_func *meshpl_recv_action[8] = { 16676340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 16776340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 16876340123SSam Leffler }; 16971766338SMonthadar Al Jaberi static ieee80211_recv_action_func *meshaction_recv_action[12] = { 17076340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 17176340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 17276340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 17376340123SSam Leffler }; 17476340123SSam Leffler static ieee80211_recv_action_func *vendor_recv_action[8] = { 17576340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 17676340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 17776340123SSam Leffler }; 17876340123SSam Leffler 17976340123SSam Leffler int 18076340123SSam Leffler ieee80211_recv_action_register(int cat, int act, ieee80211_recv_action_func *f) 18176340123SSam Leffler { 18276340123SSam Leffler switch (cat) { 18376340123SSam Leffler case IEEE80211_ACTION_CAT_BA: 184*a3e08d6fSRui Paulo if (act >= nitems(ba_recv_action)) 18576340123SSam Leffler break; 18676340123SSam Leffler ba_recv_action[act] = f; 18776340123SSam Leffler return 0; 18876340123SSam Leffler case IEEE80211_ACTION_CAT_HT: 189*a3e08d6fSRui Paulo if (act >= nitems(ht_recv_action)) 19076340123SSam Leffler break; 19176340123SSam Leffler ht_recv_action[act] = f; 19276340123SSam Leffler return 0; 193ebeaa1adSMonthadar Al Jaberi case IEEE80211_ACTION_CAT_SELF_PROT: 194*a3e08d6fSRui Paulo if (act >= nitems(meshpl_recv_action)) 19576340123SSam Leffler break; 19676340123SSam Leffler meshpl_recv_action[act] = f; 19776340123SSam Leffler return 0; 198bdd2a076SAdrian Chadd case IEEE80211_ACTION_CAT_MESH: 199*a3e08d6fSRui Paulo if (act >= nitems(meshaction_recv_action)) 20076340123SSam Leffler break; 20171766338SMonthadar Al Jaberi meshaction_recv_action[act] = f; 20276340123SSam Leffler return 0; 20376340123SSam Leffler case IEEE80211_ACTION_CAT_VENDOR: 204*a3e08d6fSRui Paulo if (act >= nitems(vendor_recv_action)) 20576340123SSam Leffler break; 20676340123SSam Leffler vendor_recv_action[act] = f; 20776340123SSam Leffler return 0; 20876340123SSam Leffler } 20976340123SSam Leffler return EINVAL; 21076340123SSam Leffler } 21176340123SSam Leffler 21276340123SSam Leffler void 21376340123SSam Leffler ieee80211_recv_action_unregister(int cat, int act) 21476340123SSam Leffler { 21576340123SSam Leffler ieee80211_recv_action_register(cat, act, recv_inval); 21676340123SSam Leffler } 21776340123SSam Leffler 21876340123SSam Leffler int 21976340123SSam Leffler ieee80211_recv_action(struct ieee80211_node *ni, 22076340123SSam Leffler const struct ieee80211_frame *wh, 22176340123SSam Leffler const uint8_t *frm, const uint8_t *efrm) 22276340123SSam Leffler { 22376340123SSam Leffler ieee80211_recv_action_func *f = recv_inval; 224cd47d75cSMonthadar Al Jaberi struct ieee80211vap *vap = ni->ni_vap; 22576340123SSam Leffler const struct ieee80211_action *ia = 22676340123SSam Leffler (const struct ieee80211_action *) frm; 22776340123SSam Leffler 22876340123SSam Leffler switch (ia->ia_category) { 22976340123SSam Leffler case IEEE80211_ACTION_CAT_BA: 230*a3e08d6fSRui Paulo if (ia->ia_action < nitems(ba_recv_action)) 23176340123SSam Leffler f = ba_recv_action[ia->ia_action]; 23276340123SSam Leffler break; 23376340123SSam Leffler case IEEE80211_ACTION_CAT_HT: 234*a3e08d6fSRui Paulo if (ia->ia_action < nitems(ht_recv_action)) 23576340123SSam Leffler f = ht_recv_action[ia->ia_action]; 23676340123SSam Leffler break; 237ebeaa1adSMonthadar Al Jaberi case IEEE80211_ACTION_CAT_SELF_PROT: 238*a3e08d6fSRui Paulo if (ia->ia_action < nitems(meshpl_recv_action)) 23976340123SSam Leffler f = meshpl_recv_action[ia->ia_action]; 24076340123SSam Leffler break; 241bdd2a076SAdrian Chadd case IEEE80211_ACTION_CAT_MESH: 242cd47d75cSMonthadar Al Jaberi if (ni == vap->iv_bss || 243cd47d75cSMonthadar Al Jaberi ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) { 244cd47d75cSMonthadar Al Jaberi IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH, 245cd47d75cSMonthadar Al Jaberi ni->ni_macaddr, NULL, 246cd47d75cSMonthadar Al Jaberi "peer link not yet established (%d), cat %s act %u", 247cd47d75cSMonthadar Al Jaberi ni->ni_mlstate, "mesh action", ia->ia_action); 248cd47d75cSMonthadar Al Jaberi vap->iv_stats.is_mesh_nolink++; 249cd47d75cSMonthadar Al Jaberi break; 250cd47d75cSMonthadar Al Jaberi } 251*a3e08d6fSRui Paulo if (ia->ia_action < nitems(meshaction_recv_action)) 25271766338SMonthadar Al Jaberi f = meshaction_recv_action[ia->ia_action]; 253bdd2a076SAdrian Chadd break; 25476340123SSam Leffler case IEEE80211_ACTION_CAT_VENDOR: 255*a3e08d6fSRui Paulo if (ia->ia_action < nitems(vendor_recv_action)) 25676340123SSam Leffler f = vendor_recv_action[ia->ia_action]; 25776340123SSam Leffler break; 25876340123SSam Leffler } 25976340123SSam Leffler return f(ni, wh, frm, efrm); 26076340123SSam Leffler } 261