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 51 static int 52 send_inval(struct ieee80211_node *ni, int cat, int act, void *sa) 53 { 54 return EINVAL; 55 } 56 57 static 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 }; 61 static 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 }; 65 static 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 }; 69 static 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 }; 74 static 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 79 static ieee80211_send_action_func *vht_send_action[3] = { 80 send_inval, send_inval, send_inval, 81 }; 82 83 int 84 ieee80211_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 121 void 122 ieee80211_send_action_unregister(int cat, int act) 123 { 124 ieee80211_send_action_register(cat, act, send_inval); 125 } 126 127 int 128 ieee80211_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 161 static int 162 recv_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 168 static 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 }; 172 static 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 }; 176 static 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 }; 180 static 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 }; 185 static 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 190 static ieee80211_recv_action_func *vht_recv_action[3] = { 191 recv_inval, recv_inval, recv_inval 192 }; 193 194 int 195 ieee80211_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 232 void 233 ieee80211_recv_action_unregister(int cat, int act) 234 { 235 ieee80211_recv_action_register(cat, act, recv_inval); 236 } 237 238 int 239 ieee80211_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