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