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: stable/11/sys/net80211/ieee80211_action.c 330470 2018-03-05 08:37:08Z eadler $"); 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> 40295126Sglebius#include <sys/malloc.h> 41195377Ssam#include <sys/systm.h> 42195377Ssam 43195377Ssam#include <sys/socket.h> 44195377Ssam 45195377Ssam#include <net/if.h> 46257176Sglebius#include <net/if_var.h> 47195377Ssam#include <net/if_media.h> 48195377Ssam#include <net/ethernet.h> 49195377Ssam 50195377Ssam#include <net80211/ieee80211_var.h> 51195377Ssam#include <net80211/ieee80211_action.h> 52195618Srpaulo#include <net80211/ieee80211_mesh.h> 53195377Ssam 54195377Ssamstatic int 55195377Ssamsend_inval(struct ieee80211_node *ni, int cat, int act, void *sa) 56195377Ssam{ 57195377Ssam return EINVAL; 58195377Ssam} 59195377Ssam 60195377Ssamstatic ieee80211_send_action_func *ba_send_action[8] = { 61195377Ssam send_inval, send_inval, send_inval, send_inval, 62195377Ssam send_inval, send_inval, send_inval, send_inval, 63195377Ssam}; 64195377Ssamstatic ieee80211_send_action_func *ht_send_action[8] = { 65195377Ssam send_inval, send_inval, send_inval, send_inval, 66195377Ssam send_inval, send_inval, send_inval, send_inval, 67195377Ssam}; 68195377Ssamstatic ieee80211_send_action_func *meshpl_send_action[8] = { 69195377Ssam send_inval, send_inval, send_inval, send_inval, 70195377Ssam send_inval, send_inval, send_inval, send_inval, 71195377Ssam}; 72246502Smonthadarstatic ieee80211_send_action_func *meshaction_send_action[12] = { 73195377Ssam send_inval, send_inval, send_inval, send_inval, 74195377Ssam send_inval, send_inval, send_inval, send_inval, 75195377Ssam send_inval, send_inval, send_inval, send_inval, 76195377Ssam}; 77195377Ssamstatic ieee80211_send_action_func *vendor_send_action[8] = { 78195377Ssam send_inval, send_inval, send_inval, send_inval, 79195377Ssam send_inval, send_inval, send_inval, send_inval, 80195377Ssam}; 81195377Ssam 82330470Seadlerstatic ieee80211_send_action_func *vht_send_action[3] = { 83330470Seadler send_inval, send_inval, send_inval, 84330470Seadler}; 85330470Seadler 86195377Ssamint 87195377Ssamieee80211_send_action_register(int cat, int act, ieee80211_send_action_func *f) 88195377Ssam{ 89195377Ssam switch (cat) { 90195377Ssam case IEEE80211_ACTION_CAT_BA: 91254315Srpaulo if (act >= nitems(ba_send_action)) 92195377Ssam break; 93195377Ssam ba_send_action[act] = f; 94195377Ssam return 0; 95195377Ssam case IEEE80211_ACTION_CAT_HT: 96254315Srpaulo if (act >= nitems(ht_send_action)) 97195377Ssam break; 98195377Ssam ht_send_action[act] = f; 99195377Ssam return 0; 100234874Smonthadar case IEEE80211_ACTION_CAT_SELF_PROT: 101254315Srpaulo if (act >= nitems(meshpl_send_action)) 102195377Ssam break; 103195377Ssam meshpl_send_action[act] = f; 104195377Ssam return 0; 105232479Sadrian case IEEE80211_ACTION_CAT_MESH: 106254315Srpaulo if (act >= nitems(meshaction_send_action)) 107246502Smonthadar break; 108246502Smonthadar meshaction_send_action[act] = f; 109246502Smonthadar return 0; 110195377Ssam case IEEE80211_ACTION_CAT_VENDOR: 111254315Srpaulo if (act >= nitems(vendor_send_action)) 112195377Ssam break; 113195377Ssam vendor_send_action[act] = f; 114195377Ssam return 0; 115330470Seadler case IEEE80211_ACTION_CAT_VHT: 116330470Seadler if (act >= nitems(vht_send_action)) 117330470Seadler break; 118330470Seadler vht_send_action[act] = f; 119330470Seadler return 0; 120195377Ssam } 121195377Ssam return EINVAL; 122195377Ssam} 123195377Ssam 124195377Ssamvoid 125195377Ssamieee80211_send_action_unregister(int cat, int act) 126195377Ssam{ 127195377Ssam ieee80211_send_action_register(cat, act, send_inval); 128195377Ssam} 129195377Ssam 130195377Ssamint 131195377Ssamieee80211_send_action(struct ieee80211_node *ni, int cat, int act, void *sa) 132195377Ssam{ 133195377Ssam ieee80211_send_action_func *f = send_inval; 134195377Ssam 135195377Ssam switch (cat) { 136195377Ssam case IEEE80211_ACTION_CAT_BA: 137254315Srpaulo if (act < nitems(ba_send_action)) 138195377Ssam f = ba_send_action[act]; 139195377Ssam break; 140195377Ssam case IEEE80211_ACTION_CAT_HT: 141254315Srpaulo if (act < nitems(ht_send_action)) 142195377Ssam f = ht_send_action[act]; 143195377Ssam break; 144234874Smonthadar case IEEE80211_ACTION_CAT_SELF_PROT: 145254315Srpaulo if (act < nitems(meshpl_send_action)) 146195377Ssam f = meshpl_send_action[act]; 147195377Ssam break; 148232479Sadrian case IEEE80211_ACTION_CAT_MESH: 149254315Srpaulo if (act < nitems(meshaction_send_action)) 150246502Smonthadar f = meshaction_send_action[act]; 151195377Ssam break; 152195377Ssam case IEEE80211_ACTION_CAT_VENDOR: 153254315Srpaulo if (act < nitems(vendor_send_action)) 154195377Ssam f = vendor_send_action[act]; 155195377Ssam break; 156330470Seadler case IEEE80211_ACTION_CAT_VHT: 157330470Seadler if (act < nitems(vht_send_action)) 158330470Seadler f = vht_send_action[act]; 159330470Seadler break; 160195377Ssam } 161195377Ssam return f(ni, cat, act, sa); 162195377Ssam} 163195377Ssam 164195377Ssamstatic int 165195377Ssamrecv_inval(struct ieee80211_node *ni, const struct ieee80211_frame *wh, 166195377Ssam const uint8_t *frm, const uint8_t *efrm) 167195377Ssam{ 168195377Ssam return EINVAL; 169195377Ssam} 170195377Ssam 171195377Ssamstatic ieee80211_recv_action_func *ba_recv_action[8] = { 172195377Ssam recv_inval, recv_inval, recv_inval, recv_inval, 173195377Ssam recv_inval, recv_inval, recv_inval, recv_inval, 174195377Ssam}; 175195377Ssamstatic ieee80211_recv_action_func *ht_recv_action[8] = { 176195377Ssam recv_inval, recv_inval, recv_inval, recv_inval, 177195377Ssam recv_inval, recv_inval, recv_inval, recv_inval, 178195377Ssam}; 179195377Ssamstatic ieee80211_recv_action_func *meshpl_recv_action[8] = { 180195377Ssam recv_inval, recv_inval, recv_inval, recv_inval, 181195377Ssam recv_inval, recv_inval, recv_inval, recv_inval, 182195377Ssam}; 183246502Smonthadarstatic ieee80211_recv_action_func *meshaction_recv_action[12] = { 184195377Ssam recv_inval, recv_inval, recv_inval, recv_inval, 185195377Ssam recv_inval, recv_inval, recv_inval, recv_inval, 186195377Ssam recv_inval, recv_inval, recv_inval, recv_inval, 187195377Ssam}; 188195377Ssamstatic ieee80211_recv_action_func *vendor_recv_action[8] = { 189195377Ssam recv_inval, recv_inval, recv_inval, recv_inval, 190195377Ssam recv_inval, recv_inval, recv_inval, recv_inval, 191195377Ssam}; 192195377Ssam 193330470Seadlerstatic ieee80211_recv_action_func *vht_recv_action[3] = { 194330470Seadler recv_inval, recv_inval, recv_inval 195330470Seadler}; 196330470Seadler 197195377Ssamint 198195377Ssamieee80211_recv_action_register(int cat, int act, ieee80211_recv_action_func *f) 199195377Ssam{ 200195377Ssam switch (cat) { 201195377Ssam case IEEE80211_ACTION_CAT_BA: 202254315Srpaulo if (act >= nitems(ba_recv_action)) 203195377Ssam break; 204195377Ssam ba_recv_action[act] = f; 205195377Ssam return 0; 206195377Ssam case IEEE80211_ACTION_CAT_HT: 207254315Srpaulo if (act >= nitems(ht_recv_action)) 208195377Ssam break; 209195377Ssam ht_recv_action[act] = f; 210195377Ssam return 0; 211234874Smonthadar case IEEE80211_ACTION_CAT_SELF_PROT: 212254315Srpaulo if (act >= nitems(meshpl_recv_action)) 213195377Ssam break; 214195377Ssam meshpl_recv_action[act] = f; 215195377Ssam return 0; 216232479Sadrian case IEEE80211_ACTION_CAT_MESH: 217254315Srpaulo if (act >= nitems(meshaction_recv_action)) 218246502Smonthadar break; 219246502Smonthadar meshaction_recv_action[act] = f; 220246502Smonthadar return 0; 221195377Ssam case IEEE80211_ACTION_CAT_VENDOR: 222254315Srpaulo if (act >= nitems(vendor_recv_action)) 223195377Ssam break; 224195377Ssam vendor_recv_action[act] = f; 225195377Ssam return 0; 226330470Seadler case IEEE80211_ACTION_CAT_VHT: 227330470Seadler if (act >= nitems(vht_recv_action)) 228330470Seadler break; 229330470Seadler vht_recv_action[act] = f; 230330470Seadler return 0; 231195377Ssam } 232195377Ssam return EINVAL; 233195377Ssam} 234195377Ssam 235195377Ssamvoid 236195377Ssamieee80211_recv_action_unregister(int cat, int act) 237195377Ssam{ 238195377Ssam ieee80211_recv_action_register(cat, act, recv_inval); 239195377Ssam} 240195377Ssam 241195377Ssamint 242195377Ssamieee80211_recv_action(struct ieee80211_node *ni, 243195377Ssam const struct ieee80211_frame *wh, 244195377Ssam const uint8_t *frm, const uint8_t *efrm) 245195377Ssam{ 246195377Ssam ieee80211_recv_action_func *f = recv_inval; 247246503Smonthadar struct ieee80211vap *vap = ni->ni_vap; 248195377Ssam const struct ieee80211_action *ia = 249195377Ssam (const struct ieee80211_action *) frm; 250195377Ssam 251195377Ssam switch (ia->ia_category) { 252195377Ssam case IEEE80211_ACTION_CAT_BA: 253254315Srpaulo if (ia->ia_action < nitems(ba_recv_action)) 254195377Ssam f = ba_recv_action[ia->ia_action]; 255195377Ssam break; 256195377Ssam case IEEE80211_ACTION_CAT_HT: 257254315Srpaulo if (ia->ia_action < nitems(ht_recv_action)) 258195377Ssam f = ht_recv_action[ia->ia_action]; 259195377Ssam break; 260234874Smonthadar case IEEE80211_ACTION_CAT_SELF_PROT: 261254315Srpaulo if (ia->ia_action < nitems(meshpl_recv_action)) 262195377Ssam f = meshpl_recv_action[ia->ia_action]; 263195377Ssam break; 264232479Sadrian case IEEE80211_ACTION_CAT_MESH: 265246503Smonthadar if (ni == vap->iv_bss || 266246503Smonthadar ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) { 267246503Smonthadar IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH, 268246503Smonthadar ni->ni_macaddr, NULL, 269246503Smonthadar "peer link not yet established (%d), cat %s act %u", 270246503Smonthadar ni->ni_mlstate, "mesh action", ia->ia_action); 271246503Smonthadar vap->iv_stats.is_mesh_nolink++; 272246503Smonthadar break; 273246503Smonthadar } 274254315Srpaulo if (ia->ia_action < nitems(meshaction_recv_action)) 275246502Smonthadar f = meshaction_recv_action[ia->ia_action]; 276195377Ssam break; 277195377Ssam case IEEE80211_ACTION_CAT_VENDOR: 278254315Srpaulo if (ia->ia_action < nitems(vendor_recv_action)) 279195377Ssam f = vendor_recv_action[ia->ia_action]; 280195377Ssam break; 281330470Seadler case IEEE80211_ACTION_CAT_VHT: 282330470Seadler if (ia->ia_action < nitems(vht_recv_action)) 283330470Seadler f = vht_recv_action[ia->ia_action]; 284330470Seadler break; 285195377Ssam } 286195377Ssam return f(ni, wh, frm, efrm); 287195377Ssam} 288