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 }; 70*71766338SMonthadar 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 #define N(a) (sizeof(a) / sizeof(a[0])) 8476340123SSam Leffler switch (cat) { 8576340123SSam Leffler case IEEE80211_ACTION_CAT_BA: 8676340123SSam Leffler if (act >= N(ba_send_action)) 8776340123SSam Leffler break; 8876340123SSam Leffler ba_send_action[act] = f; 8976340123SSam Leffler return 0; 9076340123SSam Leffler case IEEE80211_ACTION_CAT_HT: 9176340123SSam Leffler if (act >= N(ht_send_action)) 9276340123SSam Leffler break; 9376340123SSam Leffler ht_send_action[act] = f; 9476340123SSam Leffler return 0; 95ebeaa1adSMonthadar Al Jaberi case IEEE80211_ACTION_CAT_SELF_PROT: 9676340123SSam Leffler if (act >= N(meshpl_send_action)) 9776340123SSam Leffler break; 9876340123SSam Leffler meshpl_send_action[act] = f; 9976340123SSam Leffler return 0; 100bdd2a076SAdrian Chadd case IEEE80211_ACTION_CAT_MESH: 101*71766338SMonthadar Al Jaberi if (act >= N(meshaction_send_action)) 10276340123SSam Leffler break; 103*71766338SMonthadar Al Jaberi meshaction_send_action[act] = f; 10476340123SSam Leffler return 0; 105bdd2a076SAdrian Chadd break; 10676340123SSam Leffler case IEEE80211_ACTION_CAT_VENDOR: 10776340123SSam Leffler if (act >= N(vendor_send_action)) 10876340123SSam Leffler break; 10976340123SSam Leffler vendor_send_action[act] = f; 11076340123SSam Leffler return 0; 11176340123SSam Leffler } 11276340123SSam Leffler return EINVAL; 11376340123SSam Leffler #undef N 11476340123SSam Leffler } 11576340123SSam Leffler 11676340123SSam Leffler void 11776340123SSam Leffler ieee80211_send_action_unregister(int cat, int act) 11876340123SSam Leffler { 11976340123SSam Leffler ieee80211_send_action_register(cat, act, send_inval); 12076340123SSam Leffler } 12176340123SSam Leffler 12276340123SSam Leffler int 12376340123SSam Leffler ieee80211_send_action(struct ieee80211_node *ni, int cat, int act, void *sa) 12476340123SSam Leffler { 12576340123SSam Leffler #define N(a) (sizeof(a) / sizeof(a[0])) 12676340123SSam Leffler ieee80211_send_action_func *f = send_inval; 12776340123SSam Leffler 12876340123SSam Leffler switch (cat) { 12976340123SSam Leffler case IEEE80211_ACTION_CAT_BA: 13076340123SSam Leffler if (act < N(ba_send_action)) 13176340123SSam Leffler f = ba_send_action[act]; 13276340123SSam Leffler break; 13376340123SSam Leffler case IEEE80211_ACTION_CAT_HT: 13476340123SSam Leffler if (act < N(ht_send_action)) 13576340123SSam Leffler f = ht_send_action[act]; 13676340123SSam Leffler break; 137ebeaa1adSMonthadar Al Jaberi case IEEE80211_ACTION_CAT_SELF_PROT: 13876340123SSam Leffler if (act < N(meshpl_send_action)) 13976340123SSam Leffler f = meshpl_send_action[act]; 14076340123SSam Leffler break; 141bdd2a076SAdrian Chadd case IEEE80211_ACTION_CAT_MESH: 142*71766338SMonthadar Al Jaberi if (act < N(meshaction_send_action)) 143*71766338SMonthadar Al Jaberi f = meshaction_send_action[act]; 144bdd2a076SAdrian Chadd break; 14576340123SSam Leffler case IEEE80211_ACTION_CAT_VENDOR: 14676340123SSam Leffler if (act < N(vendor_send_action)) 14776340123SSam Leffler f = vendor_send_action[act]; 14876340123SSam Leffler break; 14976340123SSam Leffler } 15076340123SSam Leffler return f(ni, cat, act, sa); 15176340123SSam Leffler #undef N 15276340123SSam Leffler } 15376340123SSam Leffler 15476340123SSam Leffler static int 15576340123SSam Leffler recv_inval(struct ieee80211_node *ni, const struct ieee80211_frame *wh, 15676340123SSam Leffler const uint8_t *frm, const uint8_t *efrm) 15776340123SSam Leffler { 15876340123SSam Leffler return EINVAL; 15976340123SSam Leffler } 16076340123SSam Leffler 16176340123SSam Leffler static ieee80211_recv_action_func *ba_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 *ht_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 }; 16976340123SSam Leffler static ieee80211_recv_action_func *meshpl_recv_action[8] = { 17076340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 17176340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 17276340123SSam Leffler }; 173*71766338SMonthadar Al Jaberi static ieee80211_recv_action_func *meshaction_recv_action[12] = { 17476340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 17576340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 17676340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 17776340123SSam Leffler }; 17876340123SSam Leffler static ieee80211_recv_action_func *vendor_recv_action[8] = { 17976340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 18076340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 18176340123SSam Leffler }; 18276340123SSam Leffler 18376340123SSam Leffler int 18476340123SSam Leffler ieee80211_recv_action_register(int cat, int act, ieee80211_recv_action_func *f) 18576340123SSam Leffler { 18676340123SSam Leffler #define N(a) (sizeof(a) / sizeof(a[0])) 18776340123SSam Leffler switch (cat) { 18876340123SSam Leffler case IEEE80211_ACTION_CAT_BA: 18976340123SSam Leffler if (act >= N(ba_recv_action)) 19076340123SSam Leffler break; 19176340123SSam Leffler ba_recv_action[act] = f; 19276340123SSam Leffler return 0; 19376340123SSam Leffler case IEEE80211_ACTION_CAT_HT: 19476340123SSam Leffler if (act >= N(ht_recv_action)) 19576340123SSam Leffler break; 19676340123SSam Leffler ht_recv_action[act] = f; 19776340123SSam Leffler return 0; 198ebeaa1adSMonthadar Al Jaberi case IEEE80211_ACTION_CAT_SELF_PROT: 19976340123SSam Leffler if (act >= N(meshpl_recv_action)) 20076340123SSam Leffler break; 20176340123SSam Leffler meshpl_recv_action[act] = f; 20276340123SSam Leffler return 0; 203bdd2a076SAdrian Chadd case IEEE80211_ACTION_CAT_MESH: 204*71766338SMonthadar Al Jaberi if (act >= N(meshaction_recv_action)) 20576340123SSam Leffler break; 206*71766338SMonthadar Al Jaberi meshaction_recv_action[act] = f; 20776340123SSam Leffler return 0; 20876340123SSam Leffler case IEEE80211_ACTION_CAT_VENDOR: 20976340123SSam Leffler if (act >= N(vendor_recv_action)) 21076340123SSam Leffler break; 21176340123SSam Leffler vendor_recv_action[act] = f; 21276340123SSam Leffler return 0; 21376340123SSam Leffler } 21476340123SSam Leffler return EINVAL; 21576340123SSam Leffler #undef N 21676340123SSam Leffler } 21776340123SSam Leffler 21876340123SSam Leffler void 21976340123SSam Leffler ieee80211_recv_action_unregister(int cat, int act) 22076340123SSam Leffler { 22176340123SSam Leffler ieee80211_recv_action_register(cat, act, recv_inval); 22276340123SSam Leffler } 22376340123SSam Leffler 22476340123SSam Leffler int 22576340123SSam Leffler ieee80211_recv_action(struct ieee80211_node *ni, 22676340123SSam Leffler const struct ieee80211_frame *wh, 22776340123SSam Leffler const uint8_t *frm, const uint8_t *efrm) 22876340123SSam Leffler { 22976340123SSam Leffler #define N(a) (sizeof(a) / sizeof(a[0])) 23076340123SSam Leffler ieee80211_recv_action_func *f = recv_inval; 23176340123SSam Leffler const struct ieee80211_action *ia = 23276340123SSam Leffler (const struct ieee80211_action *) frm; 23376340123SSam Leffler 23476340123SSam Leffler switch (ia->ia_category) { 23576340123SSam Leffler case IEEE80211_ACTION_CAT_BA: 23676340123SSam Leffler if (ia->ia_action < N(ba_recv_action)) 23776340123SSam Leffler f = ba_recv_action[ia->ia_action]; 23876340123SSam Leffler break; 23976340123SSam Leffler case IEEE80211_ACTION_CAT_HT: 24076340123SSam Leffler if (ia->ia_action < N(ht_recv_action)) 24176340123SSam Leffler f = ht_recv_action[ia->ia_action]; 24276340123SSam Leffler break; 243ebeaa1adSMonthadar Al Jaberi case IEEE80211_ACTION_CAT_SELF_PROT: 24476340123SSam Leffler if (ia->ia_action < N(meshpl_recv_action)) 24576340123SSam Leffler f = meshpl_recv_action[ia->ia_action]; 24676340123SSam Leffler break; 247bdd2a076SAdrian Chadd case IEEE80211_ACTION_CAT_MESH: 248*71766338SMonthadar Al Jaberi if (ia->ia_action < N(meshaction_recv_action)) 249*71766338SMonthadar Al Jaberi f = meshaction_recv_action[ia->ia_action]; 250bdd2a076SAdrian Chadd break; 25176340123SSam Leffler case IEEE80211_ACTION_CAT_VENDOR: 25276340123SSam Leffler if (ia->ia_action < N(vendor_recv_action)) 25376340123SSam Leffler f = vendor_recv_action[ia->ia_action]; 25476340123SSam Leffler break; 25576340123SSam Leffler } 25676340123SSam Leffler return f(ni, wh, frm, efrm); 25776340123SSam Leffler #undef N 25876340123SSam Leffler } 259