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 }; 7076340123SSam Leffler static ieee80211_send_action_func *meshlm_send_action[4] = { 7176340123SSam Leffler send_inval, send_inval, send_inval, send_inval, 7276340123SSam Leffler }; 7376340123SSam Leffler static ieee80211_send_action_func *hwmp_send_action[8] = { 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 8276340123SSam Leffler int 8376340123SSam Leffler ieee80211_send_action_register(int cat, int act, ieee80211_send_action_func *f) 8476340123SSam Leffler { 8576340123SSam Leffler #define N(a) (sizeof(a) / sizeof(a[0])) 8676340123SSam Leffler switch (cat) { 8776340123SSam Leffler case IEEE80211_ACTION_CAT_BA: 8876340123SSam Leffler if (act >= N(ba_send_action)) 8976340123SSam Leffler break; 9076340123SSam Leffler ba_send_action[act] = f; 9176340123SSam Leffler return 0; 9276340123SSam Leffler case IEEE80211_ACTION_CAT_HT: 9376340123SSam Leffler if (act >= N(ht_send_action)) 9476340123SSam Leffler break; 9576340123SSam Leffler ht_send_action[act] = f; 9676340123SSam Leffler return 0; 9776340123SSam Leffler case IEEE80211_ACTION_CAT_MESHPEERING: 9876340123SSam Leffler if (act >= N(meshpl_send_action)) 9976340123SSam Leffler break; 10076340123SSam Leffler meshpl_send_action[act] = f; 10176340123SSam Leffler return 0; 10276340123SSam Leffler case IEEE80211_ACTION_CAT_MESHLMETRIC: 10376340123SSam Leffler if (act >= N(meshlm_send_action)) 10476340123SSam Leffler break; 10576340123SSam Leffler meshlm_send_action[act] = f; 10676340123SSam Leffler return 0; 10776340123SSam Leffler case IEEE80211_ACTION_CAT_MESHPATH: 10876340123SSam Leffler if (act > N(hwmp_send_action)) 10976340123SSam Leffler break; 11076340123SSam Leffler hwmp_send_action[act] = f; 11176340123SSam Leffler return 0; 11276340123SSam Leffler case IEEE80211_ACTION_CAT_VENDOR: 11376340123SSam Leffler if (act >= N(vendor_send_action)) 11476340123SSam Leffler break; 11576340123SSam Leffler vendor_send_action[act] = f; 11676340123SSam Leffler return 0; 11776340123SSam Leffler } 11876340123SSam Leffler return EINVAL; 11976340123SSam Leffler #undef N 12076340123SSam Leffler } 12176340123SSam Leffler 12276340123SSam Leffler void 12376340123SSam Leffler ieee80211_send_action_unregister(int cat, int act) 12476340123SSam Leffler { 12576340123SSam Leffler ieee80211_send_action_register(cat, act, send_inval); 12676340123SSam Leffler } 12776340123SSam Leffler 12876340123SSam Leffler int 12976340123SSam Leffler ieee80211_send_action(struct ieee80211_node *ni, int cat, int act, void *sa) 13076340123SSam Leffler { 13176340123SSam Leffler #define N(a) (sizeof(a) / sizeof(a[0])) 13276340123SSam Leffler ieee80211_send_action_func *f = send_inval; 13376340123SSam Leffler 13476340123SSam Leffler switch (cat) { 13576340123SSam Leffler case IEEE80211_ACTION_CAT_BA: 13676340123SSam Leffler if (act < N(ba_send_action)) 13776340123SSam Leffler f = ba_send_action[act]; 13876340123SSam Leffler break; 13976340123SSam Leffler case IEEE80211_ACTION_CAT_HT: 14076340123SSam Leffler if (act < N(ht_send_action)) 14176340123SSam Leffler f = ht_send_action[act]; 14276340123SSam Leffler break; 14376340123SSam Leffler case IEEE80211_ACTION_CAT_MESHPEERING: 14476340123SSam Leffler if (act < N(meshpl_send_action)) 14576340123SSam Leffler f = meshpl_send_action[act]; 14676340123SSam Leffler break; 14776340123SSam Leffler case IEEE80211_ACTION_CAT_MESHLMETRIC: 14876340123SSam Leffler if (act < N(meshlm_send_action)) 14976340123SSam Leffler f = meshlm_send_action[act]; 15076340123SSam Leffler break; 15176340123SSam Leffler case IEEE80211_ACTION_CAT_MESHPATH: 15276340123SSam Leffler if (act < N(hwmp_send_action)) 15376340123SSam Leffler f = hwmp_send_action[act]; 15476340123SSam Leffler break; 15576340123SSam Leffler case IEEE80211_ACTION_CAT_VENDOR: 15676340123SSam Leffler if (act < N(vendor_send_action)) 15776340123SSam Leffler f = vendor_send_action[act]; 15876340123SSam Leffler break; 15976340123SSam Leffler } 16076340123SSam Leffler return f(ni, cat, act, sa); 16176340123SSam Leffler #undef N 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 }; 18376340123SSam Leffler static ieee80211_recv_action_func *meshlm_recv_action[4] = { 18476340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 18576340123SSam Leffler }; 18676340123SSam Leffler static ieee80211_recv_action_func *hwmp_recv_action[8] = { 18776340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 18876340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 18976340123SSam Leffler }; 19076340123SSam Leffler static ieee80211_recv_action_func *vendor_recv_action[8] = { 19176340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 19276340123SSam Leffler recv_inval, recv_inval, recv_inval, recv_inval, 19376340123SSam Leffler }; 19476340123SSam Leffler 19576340123SSam Leffler int 19676340123SSam Leffler ieee80211_recv_action_register(int cat, int act, ieee80211_recv_action_func *f) 19776340123SSam Leffler { 19876340123SSam Leffler #define N(a) (sizeof(a) / sizeof(a[0])) 19976340123SSam Leffler switch (cat) { 20076340123SSam Leffler case IEEE80211_ACTION_CAT_BA: 20176340123SSam Leffler if (act >= N(ba_recv_action)) 20276340123SSam Leffler break; 20376340123SSam Leffler ba_recv_action[act] = f; 20476340123SSam Leffler return 0; 20576340123SSam Leffler case IEEE80211_ACTION_CAT_HT: 20676340123SSam Leffler if (act >= N(ht_recv_action)) 20776340123SSam Leffler break; 20876340123SSam Leffler ht_recv_action[act] = f; 20976340123SSam Leffler return 0; 21076340123SSam Leffler case IEEE80211_ACTION_CAT_MESHPEERING: 21176340123SSam Leffler if (act >= N(meshpl_recv_action)) 21276340123SSam Leffler break; 21376340123SSam Leffler meshpl_recv_action[act] = f; 21476340123SSam Leffler return 0; 21576340123SSam Leffler case IEEE80211_ACTION_CAT_MESHLMETRIC: 21676340123SSam Leffler if (act >= N(meshlm_recv_action)) 21776340123SSam Leffler break; 21876340123SSam Leffler meshlm_recv_action[act] = f; 21976340123SSam Leffler return 0; 22076340123SSam Leffler case IEEE80211_ACTION_CAT_MESHPATH: 22176340123SSam Leffler if (act >= N(hwmp_recv_action)) 22276340123SSam Leffler break; 22376340123SSam Leffler hwmp_recv_action[act] = f; 22476340123SSam Leffler return 0; 22576340123SSam Leffler case IEEE80211_ACTION_CAT_VENDOR: 22676340123SSam Leffler if (act >= N(vendor_recv_action)) 22776340123SSam Leffler break; 22876340123SSam Leffler vendor_recv_action[act] = f; 22976340123SSam Leffler return 0; 23076340123SSam Leffler } 23176340123SSam Leffler return EINVAL; 23276340123SSam Leffler #undef N 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 #define N(a) (sizeof(a) / sizeof(a[0])) 24776340123SSam Leffler ieee80211_recv_action_func *f = recv_inval; 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: 25376340123SSam Leffler if (ia->ia_action < N(ba_recv_action)) 25476340123SSam Leffler f = ba_recv_action[ia->ia_action]; 25576340123SSam Leffler break; 25676340123SSam Leffler case IEEE80211_ACTION_CAT_HT: 25776340123SSam Leffler if (ia->ia_action < N(ht_recv_action)) 25876340123SSam Leffler f = ht_recv_action[ia->ia_action]; 25976340123SSam Leffler break; 26076340123SSam Leffler case IEEE80211_ACTION_CAT_MESHPEERING: 26176340123SSam Leffler if (ia->ia_action < N(meshpl_recv_action)) 26276340123SSam Leffler f = meshpl_recv_action[ia->ia_action]; 26376340123SSam Leffler break; 26476340123SSam Leffler case IEEE80211_ACTION_CAT_MESHLMETRIC: 26576340123SSam Leffler if (ia->ia_action < N(meshlm_recv_action)) 26676340123SSam Leffler f = meshlm_recv_action[ia->ia_action]; 26776340123SSam Leffler break; 26876340123SSam Leffler case IEEE80211_ACTION_CAT_MESHPATH: 26976340123SSam Leffler if (ia->ia_action < N(hwmp_recv_action)) 27076340123SSam Leffler f = hwmp_recv_action[ia->ia_action]; 27176340123SSam Leffler break; 27276340123SSam Leffler case IEEE80211_ACTION_CAT_VENDOR: 27376340123SSam Leffler if (ia->ia_action < N(vendor_recv_action)) 27476340123SSam Leffler f = vendor_recv_action[ia->ia_action]; 27576340123SSam Leffler break; 27676340123SSam Leffler } 27776340123SSam Leffler return f(ni, wh, frm, efrm); 27876340123SSam Leffler #undef N 27976340123SSam Leffler } 280