1/*- 2 * SPDX-License-Identifier: BSD-2-Clause 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/* 29 * IEEE 802.11 send/recv action frame support. 30 */ 31 32#include "opt_inet.h" 33#include "opt_wlan.h" 34 35#include <sys/param.h> 36#include <sys/kernel.h> 37#include <sys/malloc.h> 38#include <sys/systm.h> 39 40#include <sys/socket.h> 41 42#include <net/if.h> 43#include <net/if_var.h> 44#include <net/if_media.h> 45#include <net/ethernet.h> 46 47#include <net80211/ieee80211_var.h> 48#include <net80211/ieee80211_action.h> 49#include <net80211/ieee80211_mesh.h> 50 51static int 52send_inval(struct ieee80211_node *ni, int cat, int act, void *sa) 53{ 54 return EINVAL; 55} 56 57static ieee80211_send_action_func *ba_send_action[8] = { 58 send_inval, send_inval, send_inval, send_inval, 59 send_inval, send_inval, send_inval, send_inval, 60}; 61static ieee80211_send_action_func *ht_send_action[8] = { 62 send_inval, send_inval, send_inval, send_inval, 63 send_inval, send_inval, send_inval, send_inval, 64}; 65static ieee80211_send_action_func *meshpl_send_action[8] = { 66 send_inval, send_inval, send_inval, send_inval, 67 send_inval, send_inval, send_inval, send_inval, 68}; 69static ieee80211_send_action_func *meshaction_send_action[12] = { 70 send_inval, send_inval, send_inval, send_inval, 71 send_inval, send_inval, send_inval, send_inval, 72 send_inval, send_inval, send_inval, send_inval, 73}; 74static ieee80211_send_action_func *vendor_send_action[8] = { 75 send_inval, send_inval, send_inval, send_inval, 76 send_inval, send_inval, send_inval, send_inval, 77}; 78 79static ieee80211_send_action_func *vht_send_action[3] = { 80 send_inval, send_inval, send_inval, 81}; 82 83int 84ieee80211_send_action_register(int cat, int act, ieee80211_send_action_func *f) 85{ 86 switch (cat) { 87 case IEEE80211_ACTION_CAT_BA: 88 if (act >= nitems(ba_send_action)) 89 break; 90 ba_send_action[act] = f; 91 return 0; 92 case IEEE80211_ACTION_CAT_HT: 93 if (act >= nitems(ht_send_action)) 94 break; 95 ht_send_action[act] = f; 96 return 0; 97 case IEEE80211_ACTION_CAT_SELF_PROT: 98 if (act >= nitems(meshpl_send_action)) 99 break; 100 meshpl_send_action[act] = f; 101 return 0; 102 case IEEE80211_ACTION_CAT_MESH: 103 if (act >= nitems(meshaction_send_action)) 104 break; 105 meshaction_send_action[act] = f; 106 return 0; 107 case IEEE80211_ACTION_CAT_VENDOR: 108 if (act >= nitems(vendor_send_action)) 109 break; 110 vendor_send_action[act] = f; 111 return 0; 112 case IEEE80211_ACTION_CAT_VHT: 113 if (act >= nitems(vht_send_action)) 114 break; 115 vht_send_action[act] = f; 116 return 0; 117 } 118 return EINVAL; 119} 120 121void 122ieee80211_send_action_unregister(int cat, int act) 123{ 124 ieee80211_send_action_register(cat, act, send_inval); 125} 126 127int 128ieee80211_send_action(struct ieee80211_node *ni, int cat, int act, void *sa) 129{ 130 ieee80211_send_action_func *f = send_inval; 131 132 switch (cat) { 133 case IEEE80211_ACTION_CAT_BA: 134 if (act < nitems(ba_send_action)) 135 f = ba_send_action[act]; 136 break; 137 case IEEE80211_ACTION_CAT_HT: 138 if (act < nitems(ht_send_action)) 139 f = ht_send_action[act]; 140 break; 141 case IEEE80211_ACTION_CAT_SELF_PROT: 142 if (act < nitems(meshpl_send_action)) 143 f = meshpl_send_action[act]; 144 break; 145 case IEEE80211_ACTION_CAT_MESH: 146 if (act < nitems(meshaction_send_action)) 147 f = meshaction_send_action[act]; 148 break; 149 case IEEE80211_ACTION_CAT_VENDOR: 150 if (act < nitems(vendor_send_action)) 151 f = vendor_send_action[act]; 152 break; 153 case IEEE80211_ACTION_CAT_VHT: 154 if (act < nitems(vht_send_action)) 155 f = vht_send_action[act]; 156 break; 157 } 158 return f(ni, cat, act, sa); 159} 160 161static int 162recv_inval(struct ieee80211_node *ni, const struct ieee80211_frame *wh, 163 const uint8_t *frm, const uint8_t *efrm) 164{ 165 return EINVAL; 166} 167 168static ieee80211_recv_action_func *ba_recv_action[8] = { 169 recv_inval, recv_inval, recv_inval, recv_inval, 170 recv_inval, recv_inval, recv_inval, recv_inval, 171}; 172static ieee80211_recv_action_func *ht_recv_action[8] = { 173 recv_inval, recv_inval, recv_inval, recv_inval, 174 recv_inval, recv_inval, recv_inval, recv_inval, 175}; 176static ieee80211_recv_action_func *meshpl_recv_action[8] = { 177 recv_inval, recv_inval, recv_inval, recv_inval, 178 recv_inval, recv_inval, recv_inval, recv_inval, 179}; 180static ieee80211_recv_action_func *meshaction_recv_action[12] = { 181 recv_inval, recv_inval, recv_inval, recv_inval, 182 recv_inval, recv_inval, recv_inval, recv_inval, 183 recv_inval, recv_inval, recv_inval, recv_inval, 184}; 185static ieee80211_recv_action_func *vendor_recv_action[8] = { 186 recv_inval, recv_inval, recv_inval, recv_inval, 187 recv_inval, recv_inval, recv_inval, recv_inval, 188}; 189 190static ieee80211_recv_action_func *vht_recv_action[3] = { 191 recv_inval, recv_inval, recv_inval 192}; 193 194int 195ieee80211_recv_action_register(int cat, int act, ieee80211_recv_action_func *f) 196{ 197 switch (cat) { 198 case IEEE80211_ACTION_CAT_BA: 199 if (act >= nitems(ba_recv_action)) 200 break; 201 ba_recv_action[act] = f; 202 return 0; 203 case IEEE80211_ACTION_CAT_HT: 204 if (act >= nitems(ht_recv_action)) 205 break; 206 ht_recv_action[act] = f; 207 return 0; 208 case IEEE80211_ACTION_CAT_SELF_PROT: 209 if (act >= nitems(meshpl_recv_action)) 210 break; 211 meshpl_recv_action[act] = f; 212 return 0; 213 case IEEE80211_ACTION_CAT_MESH: 214 if (act >= nitems(meshaction_recv_action)) 215 break; 216 meshaction_recv_action[act] = f; 217 return 0; 218 case IEEE80211_ACTION_CAT_VENDOR: 219 if (act >= nitems(vendor_recv_action)) 220 break; 221 vendor_recv_action[act] = f; 222 return 0; 223 case IEEE80211_ACTION_CAT_VHT: 224 if (act >= nitems(vht_recv_action)) 225 break; 226 vht_recv_action[act] = f; 227 return 0; 228 } 229 return EINVAL; 230} 231 232void 233ieee80211_recv_action_unregister(int cat, int act) 234{ 235 ieee80211_recv_action_register(cat, act, recv_inval); 236} 237 238int 239ieee80211_recv_action(struct ieee80211_node *ni, 240 const struct ieee80211_frame *wh, 241 const uint8_t *frm, const uint8_t *efrm) 242{ 243 ieee80211_recv_action_func *f = recv_inval; 244 struct ieee80211vap *vap = ni->ni_vap; 245 const struct ieee80211_action *ia = 246 (const struct ieee80211_action *) frm; 247 248 switch (ia->ia_category) { 249 case IEEE80211_ACTION_CAT_BA: 250 if (ia->ia_action < nitems(ba_recv_action)) 251 f = ba_recv_action[ia->ia_action]; 252 break; 253 case IEEE80211_ACTION_CAT_HT: 254 if (ia->ia_action < nitems(ht_recv_action)) 255 f = ht_recv_action[ia->ia_action]; 256 break; 257 case IEEE80211_ACTION_CAT_SELF_PROT: 258 if (ia->ia_action < nitems(meshpl_recv_action)) 259 f = meshpl_recv_action[ia->ia_action]; 260 break; 261 case IEEE80211_ACTION_CAT_MESH: 262 if (ni == vap->iv_bss || 263 ni->ni_mlstate != IEEE80211_NODE_MESH_ESTABLISHED) { 264 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_MESH, 265 ni->ni_macaddr, NULL, 266 "peer link not yet established (%d), cat %s act %u", 267 ni->ni_mlstate, "mesh action", ia->ia_action); 268 vap->iv_stats.is_mesh_nolink++; 269 break; 270 } 271 if (ia->ia_action < nitems(meshaction_recv_action)) 272 f = meshaction_recv_action[ia->ia_action]; 273 break; 274 case IEEE80211_ACTION_CAT_VENDOR: 275 if (ia->ia_action < nitems(vendor_recv_action)) 276 f = vendor_recv_action[ia->ia_action]; 277 break; 278 case IEEE80211_ACTION_CAT_VHT: 279 if (ia->ia_action < nitems(vht_recv_action)) 280 f = vht_recv_action[ia->ia_action]; 281 break; 282 } 283 return f(ni, wh, frm, efrm); 284} 285