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