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 #include <sys/cdefs.h> 29 #ifdef __FreeBSD__ 30 __FBSDID("$FreeBSD$"); 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 56 static int 57 send_inval(struct ieee80211_node *ni, int cat, int act, void *sa) 58 { 59 return EINVAL; 60 } 61 62 static 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 }; 66 static 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 }; 70 static 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 }; 74 static 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 }; 79 static 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 84 static ieee80211_send_action_func *vht_send_action[3] = { 85 send_inval, send_inval, send_inval, 86 }; 87 88 int 89 ieee80211_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 126 void 127 ieee80211_send_action_unregister(int cat, int act) 128 { 129 ieee80211_send_action_register(cat, act, send_inval); 130 } 131 132 int 133 ieee80211_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 166 static int 167 recv_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 173 static 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 }; 177 static 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 }; 181 static 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 }; 185 static 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 }; 190 static 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 195 static ieee80211_recv_action_func *vht_recv_action[3] = { 196 recv_inval, recv_inval, recv_inval 197 }; 198 199 int 200 ieee80211_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 237 void 238 ieee80211_recv_action_unregister(int cat, int act) 239 { 240 ieee80211_recv_action_register(cat, act, recv_inval); 241 } 242 243 int 244 ieee80211_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