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> 408ec07310SGleb Smirnoff #include <sys/malloc.h> 4176340123SSam Leffler #include <sys/systm.h> 4276340123SSam Leffler 4376340123SSam Leffler #include <sys/socket.h> 4476340123SSam Leffler 4576340123SSam Leffler #include <net/if.h> 4676039bc8SGleb Smirnoff #include <net/if_var.h> 4776340123SSam Leffler #include <net/if_media.h> 4876340123SSam Leffler #include <net/ethernet.h> 4976340123SSam Leffler 5076340123SSam Leffler #include <net80211/ieee80211_var.h> 5176340123SSam Leffler #include <net80211/ieee80211_action.h> 5259aa14a9SRui Paulo #include <net80211/ieee80211_mesh.h> 5376340123SSam Leffler 5476340123SSam Leffler static int 5576340123SSam Leffler send_inval(struct ieee80211_node *ni, int cat, int act, void *sa) 5676340123SSam Leffler { 5776340123SSam Leffler return EINVAL; 5876340123SSam Leffler } 5976340123SSam Leffler 6076340123SSam Leffler static ieee80211_send_action_func *ba_send_action[8] = { 6176340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 6276340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 6376340123SSam Leffler }; 6476340123SSam Leffler static ieee80211_send_action_func *ht_send_action[8] = { 6576340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 6676340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 6776340123SSam Leffler }; 6876340123SSam Leffler static ieee80211_send_action_func *meshpl_send_action[8] = { 6976340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 7076340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 7176340123SSam Leffler }; 7271766338SMonthadar Al Jaberi static ieee80211_send_action_func *meshaction_send_action[12] = { 7376340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 7476340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 7576340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 7676340123SSam Leffler }; 7776340123SSam Leffler static ieee80211_send_action_func *vendor_send_action[8] = { 7876340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 7976340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 8076340123SSam Leffler }; 8176340123SSam Leffler 82*7c87f23eSAdrian Chadd static ieee80211_send_action_func *vht_send_action[3] = { 83*7c87f23eSAdrian Chadd send_inval, send_inval, send_inval, 84*7c87f23eSAdrian Chadd }; 85*7c87f23eSAdrian Chadd 8676340123SSam Leffler int 8776340123SSam Leffler ieee80211_send_action_register(int cat, int act, ieee80211_send_action_func *f) 8876340123SSam Leffler { 8976340123SSam Leffler switch (cat) { 9076340123SSam Leffler case IEEE80211_ACTION_CAT_BA: 91a3e08d6fSRui Paulo if (act >= nitems(ba_send_action)) 9276340123SSam Leffler break; 9376340123SSam Leffler ba_send_action[act] = f; 9476340123SSam Leffler return 0; 9576340123SSam Leffler case IEEE80211_ACTION_CAT_HT: 96a3e08d6fSRui Paulo if (act >= nitems(ht_send_action)) 9776340123SSam Leffler break; 9876340123SSam Leffler ht_send_action[act] = f; 9976340123SSam Leffler return 0; 100ebeaa1adSMonthadar Al Jaberi case IEEE80211_ACTION_CAT_SELF_PROT: 101a3e08d6fSRui Paulo if (act >= nitems(meshpl_send_action)) 10276340123SSam Leffler break; 10376340123SSam Leffler meshpl_send_action[act] = f; 10476340123SSam Leffler return 0; 105bdd2a076SAdrian Chadd case IEEE80211_ACTION_CAT_MESH: 106a3e08d6fSRui Paulo if (act >= nitems(meshaction_send_action)) 10776340123SSam Leffler break; 10871766338SMonthadar Al Jaberi meshaction_send_action[act] = f; 10976340123SSam Leffler return 0; 11076340123SSam Leffler case IEEE80211_ACTION_CAT_VENDOR: 111a3e08d6fSRui Paulo if (act >= nitems(vendor_send_action)) 11276340123SSam Leffler break; 11376340123SSam Leffler vendor_send_action[act] = f; 11476340123SSam Leffler return 0; 115*7c87f23eSAdrian Chadd case IEEE80211_ACTION_CAT_VHT: 116*7c87f23eSAdrian Chadd if (act >= nitems(vht_send_action)) 117*7c87f23eSAdrian Chadd break; 118*7c87f23eSAdrian Chadd vht_send_action[act] = f; 119*7c87f23eSAdrian Chadd return 0; 12076340123SSam Leffler } 12176340123SSam Leffler return EINVAL; 12276340123SSam Leffler } 12376340123SSam Leffler 12476340123SSam Leffler void 12576340123SSam Leffler ieee80211_send_action_unregister(int cat, int act) 12676340123SSam Leffler { 12776340123SSam Leffler ieee80211_send_action_register(cat, act, send_inval); 12876340123SSam Leffler } 12976340123SSam Leffler 13076340123SSam Leffler int 13176340123SSam Leffler ieee80211_send_action(struct ieee80211_node *ni, int cat, int act, void *sa) 13276340123SSam Leffler { 13376340123SSam Leffler ieee80211_send_action_func *f = send_inval; 13476340123SSam Leffler 13576340123SSam Leffler switch (cat) { 13676340123SSam Leffler case IEEE80211_ACTION_CAT_BA: 137a3e08d6fSRui Paulo if (act < nitems(ba_send_action)) 13876340123SSam Leffler f = ba_send_action[act]; 13976340123SSam Leffler break; 14076340123SSam Leffler case IEEE80211_ACTION_CAT_HT: 141a3e08d6fSRui Paulo if (act < nitems(ht_send_action)) 14276340123SSam Leffler f = ht_send_action[act]; 14376340123SSam Leffler break; 144ebeaa1adSMonthadar Al Jaberi case IEEE80211_ACTION_CAT_SELF_PROT: 145a3e08d6fSRui Paulo if (act < nitems(meshpl_send_action)) 14676340123SSam Leffler f = meshpl_send_action[act]; 14776340123SSam Leffler break; 148bdd2a076SAdrian Chadd case IEEE80211_ACTION_CAT_MESH: 149a3e08d6fSRui Paulo if (act < nitems(meshaction_send_action)) 15071766338SMonthadar Al Jaberi f = meshaction_send_action[act]; 151bdd2a076SAdrian Chadd break; 15276340123SSam Leffler case IEEE80211_ACTION_CAT_VENDOR: 153a3e08d6fSRui Paulo if (act < nitems(vendor_send_action)) 15476340123SSam Leffler f = vendor_send_action[act]; 15576340123SSam Leffler break; 156*7c87f23eSAdrian Chadd case IEEE80211_ACTION_CAT_VHT: 157*7c87f23eSAdrian Chadd if (act < nitems(vht_send_action)) 158*7c87f23eSAdrian Chadd f = vht_send_action[act]; 159*7c87f23eSAdrian Chadd break; 16076340123SSam Leffler } 16176340123SSam Leffler return f(ni, cat, act, sa); 16276340123SSam Leffler } 16376340123SSam Leffler 16476340123SSam Leffler static int 16576340123SSam Leffler recv_inval(struct ieee80211_node *ni, const struct ieee80211_frame *wh, 16676340123SSam Leffler const uint8_t *frm, const uint8_t *efrm) 16776340123SSam Leffler { 16876340123SSam Leffler return EINVAL; 16976340123SSam Leffler } 17076340123SSam Leffler 17176340123SSam Leffler static ieee80211_recv_action_func *ba_recv_action[8] = { 17276340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 17376340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 17476340123SSam Leffler }; 17576340123SSam Leffler static ieee80211_recv_action_func *ht_recv_action[8] = { 17676340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 17776340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 17876340123SSam Leffler }; 17976340123SSam Leffler static ieee80211_recv_action_func *meshpl_recv_action[8] = { 18076340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 18176340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 18276340123SSam Leffler }; 18371766338SMonthadar Al Jaberi static ieee80211_recv_action_func *meshaction_recv_action[12] = { 18476340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 18576340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 18676340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 18776340123SSam Leffler }; 18876340123SSam Leffler static ieee80211_recv_action_func *vendor_recv_action[8] = { 18976340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 19076340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 19176340123SSam Leffler }; 19276340123SSam Leffler 193*7c87f23eSAdrian Chadd static ieee80211_recv_action_func *vht_recv_action[3] = { 194*7c87f23eSAdrian Chadd recv_inval, recv_inval, recv_inval 195*7c87f23eSAdrian Chadd }; 196*7c87f23eSAdrian Chadd 19776340123SSam Leffler int 19876340123SSam Leffler ieee80211_recv_action_register(int cat, int act, ieee80211_recv_action_func *f) 19976340123SSam Leffler { 20076340123SSam Leffler switch (cat) { 20176340123SSam Leffler case IEEE80211_ACTION_CAT_BA: 202a3e08d6fSRui Paulo if (act >= nitems(ba_recv_action)) 20376340123SSam Leffler break; 20476340123SSam Leffler ba_recv_action[act] = f; 20576340123SSam Leffler return 0; 20676340123SSam Leffler case IEEE80211_ACTION_CAT_HT: 207a3e08d6fSRui Paulo if (act >= nitems(ht_recv_action)) 20876340123SSam Leffler break; 20976340123SSam Leffler ht_recv_action[act] = f; 21076340123SSam Leffler return 0; 211ebeaa1adSMonthadar Al Jaberi case IEEE80211_ACTION_CAT_SELF_PROT: 212a3e08d6fSRui Paulo if (act >= nitems(meshpl_recv_action)) 21376340123SSam Leffler break; 21476340123SSam Leffler meshpl_recv_action[act] = f; 21576340123SSam Leffler return 0; 216bdd2a076SAdrian Chadd case IEEE80211_ACTION_CAT_MESH: 217a3e08d6fSRui Paulo if (act >= nitems(meshaction_recv_action)) 21876340123SSam Leffler break; 21971766338SMonthadar Al Jaberi meshaction_recv_action[act] = f; 22076340123SSam Leffler return 0; 22176340123SSam Leffler case IEEE80211_ACTION_CAT_VENDOR: 222a3e08d6fSRui Paulo if (act >= nitems(vendor_recv_action)) 22376340123SSam Leffler break; 22476340123SSam Leffler vendor_recv_action[act] = f; 22576340123SSam Leffler return 0; 226*7c87f23eSAdrian Chadd case IEEE80211_ACTION_CAT_VHT: 227*7c87f23eSAdrian Chadd if (act >= nitems(vht_recv_action)) 228*7c87f23eSAdrian Chadd break; 229*7c87f23eSAdrian Chadd vht_recv_action[act] = f; 230*7c87f23eSAdrian Chadd return 0; 23176340123SSam Leffler } 23276340123SSam Leffler return EINVAL; 23376340123SSam Leffler } 23476340123SSam Leffler 23576340123SSam Leffler void 23676340123SSam Leffler ieee80211_recv_action_unregister(int cat, int act) 23776340123SSam Leffler { 23876340123SSam Leffler ieee80211_recv_action_register(cat, act, recv_inval); 23976340123SSam Leffler } 24076340123SSam Leffler 24176340123SSam Leffler int 24276340123SSam Leffler ieee80211_recv_action(struct ieee80211_node *ni, 24376340123SSam Leffler const struct ieee80211_frame *wh, 24476340123SSam Leffler const uint8_t *frm, const uint8_t *efrm) 24576340123SSam Leffler { 24676340123SSam Leffler ieee80211_recv_action_func *f = recv_inval; 247cd47d75cSMonthadar Al Jaberi struct ieee80211vap *vap = ni->ni_vap; 24876340123SSam Leffler const struct ieee80211_action *ia = 24976340123SSam Leffler (const struct ieee80211_action *) frm; 25076340123SSam Leffler 25176340123SSam Leffler switch (ia->ia_category) { 25276340123SSam Leffler case IEEE80211_ACTION_CAT_BA: 253a3e08d6fSRui Paulo if (ia->ia_action < nitems(ba_recv_action)) 25476340123SSam Leffler f = ba_recv_action[ia->ia_action]; 25576340123SSam Leffler break; 25676340123SSam Leffler case IEEE80211_ACTION_CAT_HT: 257a3e08d6fSRui Paulo if (ia->ia_action < nitems(ht_recv_action)) 25876340123SSam Leffler f = ht_recv_action[ia->ia_action]; 25976340123SSam Leffler break; 260ebeaa1adSMonthadar Al Jaberi case IEEE80211_ACTION_CAT_SELF_PROT: 261a3e08d6fSRui Paulo if (ia->ia_action < nitems(meshpl_recv_action)) 26276340123SSam Leffler f = meshpl_recv_action[ia->ia_action]; 26376340123SSam Leffler break; 264bdd2a076SAdrian Chadd case IEEE80211_ACTION_CAT_MESH: 265cd47d75cSMonthadar Al Jaberi if (ni == vap->iv_bss || 266cd47d75cSMonthadar Al Jaberi ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) { 267cd47d75cSMonthadar Al Jaberi IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH, 268cd47d75cSMonthadar Al Jaberi ni->ni_macaddr, NULL, 269cd47d75cSMonthadar Al Jaberi "peer link not yet established (%d), cat %s act %u", 270cd47d75cSMonthadar Al Jaberi ni->ni_mlstate, "mesh action", ia->ia_action); 271cd47d75cSMonthadar Al Jaberi vap->iv_stats.is_mesh_nolink++; 272cd47d75cSMonthadar Al Jaberi break; 273cd47d75cSMonthadar Al Jaberi } 274a3e08d6fSRui Paulo if (ia->ia_action < nitems(meshaction_recv_action)) 27571766338SMonthadar Al Jaberi f = meshaction_recv_action[ia->ia_action]; 276bdd2a076SAdrian Chadd break; 27776340123SSam Leffler case IEEE80211_ACTION_CAT_VENDOR: 278a3e08d6fSRui Paulo if (ia->ia_action < nitems(vendor_recv_action)) 27976340123SSam Leffler f = vendor_recv_action[ia->ia_action]; 28076340123SSam Leffler break; 281*7c87f23eSAdrian Chadd case IEEE80211_ACTION_CAT_VHT: 282*7c87f23eSAdrian Chadd if (ia->ia_action < nitems(vht_recv_action)) 283*7c87f23eSAdrian Chadd f = vht_recv_action[ia->ia_action]; 284*7c87f23eSAdrian Chadd break; 28576340123SSam Leffler } 28676340123SSam Leffler return f(ni, wh, frm, efrm); 28776340123SSam Leffler } 288