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