1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2009 Sam Leffler, Errno Consulting 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29#ifdef __FreeBSD__ 30__FBSDID("$FreeBSD: releng/12.0/sys/net80211/ieee80211_action.c 326272 2017-11-27 15:23:17Z pfg $"); 31#endif 32 33/* 34 * IEEE 802.11 send/recv action frame support. 35 */ 36 37#include "opt_inet.h" 38#include "opt_wlan.h" 39 40#include <sys/param.h> 41#include <sys/kernel.h> 42#include <sys/malloc.h> 43#include <sys/systm.h> 44 45#include <sys/socket.h> 46 47#include <net/if.h> 48#include <net/if_var.h> 49#include <net/if_media.h> 50#include <net/ethernet.h> 51 52#include <net80211/ieee80211_var.h> 53#include <net80211/ieee80211_action.h> 54#include <net80211/ieee80211_mesh.h> 55 56static int 57send_inval(struct ieee80211_node *ni, int cat, int act, void *sa) 58{ 59 return EINVAL; 60} 61 62static ieee80211_send_action_func *ba_send_action[8] = { 63 send_inval, send_inval, send_inval, send_inval, 64 send_inval, send_inval, send_inval, send_inval, 65}; 66static ieee80211_send_action_func *ht_send_action[8] = { 67 send_inval, send_inval, send_inval, send_inval, 68 send_inval, send_inval, send_inval, send_inval, 69}; 70static ieee80211_send_action_func *meshpl_send_action[8] = { 71 send_inval, send_inval, send_inval, send_inval, 72 send_inval, send_inval, send_inval, send_inval, 73}; 74static ieee80211_send_action_func *meshaction_send_action[12] = { 75 send_inval, send_inval, send_inval, send_inval, 76 send_inval, send_inval, send_inval, send_inval, 77 send_inval, send_inval, send_inval, send_inval, 78}; 79static ieee80211_send_action_func *vendor_send_action[8] = { 80 send_inval, send_inval, send_inval, send_inval, 81 send_inval, send_inval, send_inval, send_inval, 82}; 83 84static ieee80211_send_action_func *vht_send_action[3] = { 85 send_inval, send_inval, send_inval, 86}; 87 88int 89ieee80211_send_action_register(int cat, int act, ieee80211_send_action_func *f) 90{ 91 switch (cat) { 92 case IEEE80211_ACTION_CAT_BA: 93 if (act >= nitems(ba_send_action)) 94 break; 95 ba_send_action[act] = f; 96 return 0; 97 case IEEE80211_ACTION_CAT_HT: 98 if (act >= nitems(ht_send_action)) 99 break; 100 ht_send_action[act] = f; 101 return 0; 102 case IEEE80211_ACTION_CAT_SELF_PROT: 103 if (act >= nitems(meshpl_send_action)) 104 break; 105 meshpl_send_action[act] = f; 106 return 0; 107 case IEEE80211_ACTION_CAT_MESH: 108 if (act >= nitems(meshaction_send_action)) 109 break; 110 meshaction_send_action[act] = f; 111 return 0; 112 case IEEE80211_ACTION_CAT_VENDOR: 113 if (act >= nitems(vendor_send_action)) 114 break; 115 vendor_send_action[act] = f; 116 return 0; 117 case IEEE80211_ACTION_CAT_VHT: 118 if (act >= nitems(vht_send_action)) 119 break; 120 vht_send_action[act] = f; 121 return 0; 122 } 123 return EINVAL; 124} 125 126void 127ieee80211_send_action_unregister(int cat, int act) 128{ 129 ieee80211_send_action_register(cat, act, send_inval); 130} 131 132int 133ieee80211_send_action(struct ieee80211_node *ni, int cat, int act, void *sa) 134{ 135 ieee80211_send_action_func *f = send_inval; 136 137 switch (cat) { 138 case IEEE80211_ACTION_CAT_BA: 139 if (act < nitems(ba_send_action)) 140 f = ba_send_action[act]; 141 break; 142 case IEEE80211_ACTION_CAT_HT: 143 if (act < nitems(ht_send_action)) 144 f = ht_send_action[act]; 145 break; 146 case IEEE80211_ACTION_CAT_SELF_PROT: 147 if (act < nitems(meshpl_send_action)) 148 f = meshpl_send_action[act]; 149 break; 150 case IEEE80211_ACTION_CAT_MESH: 151 if (act < nitems(meshaction_send_action)) 152 f = meshaction_send_action[act]; 153 break; 154 case IEEE80211_ACTION_CAT_VENDOR: 155 if (act < nitems(vendor_send_action)) 156 f = vendor_send_action[act]; 157 break; 158 case IEEE80211_ACTION_CAT_VHT: 159 if (act < nitems(vht_send_action)) 160 f = vht_send_action[act]; 161 break; 162 } 163 return f(ni, cat, act, sa); 164} 165 166static int 167recv_inval(struct ieee80211_node *ni, const struct ieee80211_frame *wh, 168 const uint8_t *frm, const uint8_t *efrm) 169{ 170 return EINVAL; 171} 172 173static ieee80211_recv_action_func *ba_recv_action[8] = { 174 recv_inval, recv_inval, recv_inval, recv_inval, 175 recv_inval, recv_inval, recv_inval, recv_inval, 176}; 177static ieee80211_recv_action_func *ht_recv_action[8] = { 178 recv_inval, recv_inval, recv_inval, recv_inval, 179 recv_inval, recv_inval, recv_inval, recv_inval, 180}; 181static ieee80211_recv_action_func *meshpl_recv_action[8] = { 182 recv_inval, recv_inval, recv_inval, recv_inval, 183 recv_inval, recv_inval, recv_inval, recv_inval, 184}; 185static ieee80211_recv_action_func *meshaction_recv_action[12] = { 186 recv_inval, recv_inval, recv_inval, recv_inval, 187 recv_inval, recv_inval, recv_inval, recv_inval, 188 recv_inval, recv_inval, recv_inval, recv_inval, 189}; 190static ieee80211_recv_action_func *vendor_recv_action[8] = { 191 recv_inval, recv_inval, recv_inval, recv_inval, 192 recv_inval, recv_inval, recv_inval, recv_inval, 193}; 194 195static ieee80211_recv_action_func *vht_recv_action[3] = { 196 recv_inval, recv_inval, recv_inval 197}; 198 199int 200ieee80211_recv_action_register(int cat, int act, ieee80211_recv_action_func *f) 201{ 202 switch (cat) { 203 case IEEE80211_ACTION_CAT_BA: 204 if (act >= nitems(ba_recv_action)) 205 break; 206 ba_recv_action[act] = f; 207 return 0; 208 case IEEE80211_ACTION_CAT_HT: 209 if (act >= nitems(ht_recv_action)) 210 break; 211 ht_recv_action[act] = f; 212 return 0; 213 case IEEE80211_ACTION_CAT_SELF_PROT: 214 if (act >= nitems(meshpl_recv_action)) 215 break; 216 meshpl_recv_action[act] = f; 217 return 0; 218 case IEEE80211_ACTION_CAT_MESH: 219 if (act >= nitems(meshaction_recv_action)) 220 break; 221 meshaction_recv_action[act] = f; 222 return 0; 223 case IEEE80211_ACTION_CAT_VENDOR: 224 if (act >= nitems(vendor_recv_action)) 225 break; 226 vendor_recv_action[act] = f; 227 return 0; 228 case IEEE80211_ACTION_CAT_VHT: 229 if (act >= nitems(vht_recv_action)) 230 break; 231 vht_recv_action[act] = f; 232 return 0; 233 } 234 return EINVAL; 235} 236 237void 238ieee80211_recv_action_unregister(int cat, int act) 239{ 240 ieee80211_recv_action_register(cat, act, recv_inval); 241} 242 243int 244ieee80211_recv_action(struct ieee80211_node *ni, 245 const struct ieee80211_frame *wh, 246 const uint8_t *frm, const uint8_t *efrm) 247{ 248 ieee80211_recv_action_func *f = recv_inval; 249 struct ieee80211vap *vap = ni->ni_vap; 250 const struct ieee80211_action *ia = 251 (const struct ieee80211_action *) frm; 252 253 switch (ia->ia_category) { 254 case IEEE80211_ACTION_CAT_BA: 255 if (ia->ia_action < nitems(ba_recv_action)) 256 f = ba_recv_action[ia->ia_action]; 257 break; 258 case IEEE80211_ACTION_CAT_HT: 259 if (ia->ia_action < nitems(ht_recv_action)) 260 f = ht_recv_action[ia->ia_action]; 261 break; 262 case IEEE80211_ACTION_CAT_SELF_PROT: 263 if (ia->ia_action < nitems(meshpl_recv_action)) 264 f = meshpl_recv_action[ia->ia_action]; 265 break; 266 case IEEE80211_ACTION_CAT_MESH: 267 if (ni == vap->iv_bss || 268 ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) { 269 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH, 270 ni->ni_macaddr, NULL, 271 "peer link not yet established (%d), cat %s act %u", 272 ni->ni_mlstate, "mesh action", ia->ia_action); 273 vap->iv_stats.is_mesh_nolink++; 274 break; 275 } 276 if (ia->ia_action < nitems(meshaction_recv_action)) 277 f = meshaction_recv_action[ia->ia_action]; 278 break; 279 case IEEE80211_ACTION_CAT_VENDOR: 280 if (ia->ia_action < nitems(vendor_recv_action)) 281 f = vendor_recv_action[ia->ia_action]; 282 break; 283 case IEEE80211_ACTION_CAT_VHT: 284 if (ia->ia_action < nitems(vht_recv_action)) 285 f = vht_recv_action[ia->ia_action]; 286 break; 287 } 288 return f(ni, wh, frm, efrm); 289} 290