1 1.34 maxv /* $NetBSD: ieee80211_netbsd.c,v 1.34 2018/12/22 14:28:56 maxv Exp $ */ 2 1.30 maxv 3 1.30 maxv /* 4 1.1 dyoung * Copyright (c) 2003-2005 Sam Leffler, Errno Consulting 5 1.1 dyoung * All rights reserved. 6 1.1 dyoung * 7 1.1 dyoung * Redistribution and use in source and binary forms, with or without 8 1.1 dyoung * modification, are permitted provided that the following conditions 9 1.1 dyoung * are met: 10 1.1 dyoung * 1. Redistributions of source code must retain the above copyright 11 1.1 dyoung * notice, this list of conditions and the following disclaimer. 12 1.1 dyoung * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 dyoung * notice, this list of conditions and the following disclaimer in the 14 1.1 dyoung * documentation and/or other materials provided with the distribution. 15 1.1 dyoung * 3. The name of the author may not be used to endorse or promote products 16 1.1 dyoung * derived from this software without specific prior written permission. 17 1.1 dyoung * 18 1.1 dyoung * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 1.1 dyoung * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 1.1 dyoung * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 1.1 dyoung * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 1.1 dyoung * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 1.1 dyoung * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 1.1 dyoung * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 1.1 dyoung * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 1.1 dyoung * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 1.1 dyoung * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 1.1 dyoung */ 29 1.1 dyoung 30 1.1 dyoung #include <sys/cdefs.h> 31 1.2 dyoung #ifdef __FreeBSD__ 32 1.8 skrll __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_freebsd.c,v 1.8 2005/08/08 18:46:35 sam Exp $"); 33 1.2 dyoung #else 34 1.34 maxv __KERNEL_RCSID(0, "$NetBSD: ieee80211_netbsd.c,v 1.34 2018/12/22 14:28:56 maxv Exp $"); 35 1.2 dyoung #endif 36 1.1 dyoung 37 1.1 dyoung /* 38 1.10 thorpej * IEEE 802.11 support (NetBSD-specific code) 39 1.1 dyoung */ 40 1.1 dyoung #include <sys/param.h> 41 1.1 dyoung #include <sys/kernel.h> 42 1.30 maxv #include <sys/systm.h> 43 1.30 maxv #include <sys/mbuf.h> 44 1.1 dyoung #include <sys/proc.h> 45 1.1 dyoung #include <sys/sysctl.h> 46 1.10 thorpej #include <sys/once.h> 47 1.1 dyoung 48 1.1 dyoung #include <sys/socket.h> 49 1.1 dyoung 50 1.20 tls #include <sys/cprng.h> 51 1.20 tls 52 1.1 dyoung #include <net/if.h> 53 1.1 dyoung #include <net/if_media.h> 54 1.2 dyoung #include <net/if_ether.h> 55 1.1 dyoung #include <net/route.h> 56 1.1 dyoung 57 1.2 dyoung #include <net80211/ieee80211_netbsd.h> 58 1.1 dyoung #include <net80211/ieee80211_var.h> 59 1.2 dyoung #include <net80211/ieee80211_sysctl.h> 60 1.2 dyoung 61 1.2 dyoung #define LOGICALLY_EQUAL(x, y) (!(x) == !(y)) 62 1.1 dyoung 63 1.2 dyoung static void ieee80211_sysctl_fill_node(struct ieee80211_node *, 64 1.9 dyoung struct ieee80211_node_sysctl *, int, const struct ieee80211_channel *, 65 1.9 dyoung uint32_t); 66 1.2 dyoung static struct ieee80211_node *ieee80211_node_walknext( 67 1.2 dyoung struct ieee80211_node_walk *); 68 1.2 dyoung static struct ieee80211_node *ieee80211_node_walkfirst( 69 1.2 dyoung struct ieee80211_node_walk *, u_short); 70 1.2 dyoung static int ieee80211_sysctl_node(SYSCTLFN_ARGS); 71 1.1 dyoung 72 1.26 pooka static void ieee80211_sysctl_setup(void); 73 1.26 pooka 74 1.1 dyoung #ifdef IEEE80211_DEBUG 75 1.1 dyoung int ieee80211_debug = 0; 76 1.1 dyoung #endif 77 1.1 dyoung 78 1.8 skrll typedef void (*ieee80211_setup_func)(void); 79 1.8 skrll 80 1.8 skrll __link_set_decl(ieee80211_funcs, ieee80211_setup_func); 81 1.8 skrll 82 1.12 yamt static int 83 1.10 thorpej ieee80211_init0(void) 84 1.8 skrll { 85 1.8 skrll ieee80211_setup_func * const *ieee80211_setup, f; 86 1.8 skrll 87 1.26 pooka ieee80211_sysctl_setup(); 88 1.26 pooka 89 1.22 matt if (max_linkhdr < ALIGN(sizeof(struct ieee80211_qosframe_addr4))) { 90 1.22 matt max_linkhdr = ALIGN(sizeof(struct ieee80211_qosframe_addr4)); 91 1.22 matt } 92 1.22 matt 93 1.30 maxv __link_set_foreach(ieee80211_setup, ieee80211_funcs) { 94 1.8 skrll f = (void*)*ieee80211_setup; 95 1.8 skrll (*f)(); 96 1.8 skrll } 97 1.12 yamt 98 1.12 yamt return 0; 99 1.8 skrll } 100 1.8 skrll 101 1.10 thorpej void 102 1.10 thorpej ieee80211_init(void) 103 1.10 thorpej { 104 1.10 thorpej static ONCE_DECL(ieee80211_init_once); 105 1.10 thorpej 106 1.10 thorpej RUN_ONCE(&ieee80211_init_once, ieee80211_init0); 107 1.10 thorpej } 108 1.10 thorpej 109 1.1 dyoung static int 110 1.2 dyoung ieee80211_sysctl_inact(SYSCTLFN_ARGS) 111 1.1 dyoung { 112 1.2 dyoung int error, t; 113 1.2 dyoung struct sysctlnode node; 114 1.2 dyoung 115 1.2 dyoung node = *rnode; 116 1.30 maxv 117 1.30 maxv /* 118 1.30 maxv * sysctl_lookup copies the product from t. Then, it 119 1.2 dyoung * copies the new value onto t. 120 1.2 dyoung */ 121 1.2 dyoung t = *(int*)rnode->sysctl_data * IEEE80211_INACT_WAIT; 122 1.2 dyoung node.sysctl_data = &t; 123 1.2 dyoung error = sysctl_lookup(SYSCTLFN_CALL(&node)); 124 1.2 dyoung if (error || newp == NULL) 125 1.30 maxv return error; 126 1.2 dyoung 127 1.30 maxv /* 128 1.30 maxv * The new value was in seconds. Convert to inactivity-wait 129 1.2 dyoung * intervals. There are IEEE80211_INACT_WAIT seconds per 130 1.2 dyoung * interval. 131 1.2 dyoung */ 132 1.2 dyoung *(int*)rnode->sysctl_data = t / IEEE80211_INACT_WAIT; 133 1.1 dyoung 134 1.30 maxv return 0; 135 1.1 dyoung } 136 1.1 dyoung 137 1.1 dyoung static int 138 1.2 dyoung ieee80211_sysctl_parent(SYSCTLFN_ARGS) 139 1.1 dyoung { 140 1.2 dyoung struct ieee80211com *ic; 141 1.2 dyoung char pname[IFNAMSIZ]; 142 1.2 dyoung struct sysctlnode node; 143 1.2 dyoung 144 1.2 dyoung node = *rnode; 145 1.2 dyoung ic = node.sysctl_data; 146 1.29 maya strlcpy(pname, ic->ic_ifp->if_xname, IFNAMSIZ); 147 1.2 dyoung node.sysctl_data = pname; 148 1.2 dyoung return sysctl_lookup(SYSCTLFN_CALL(&node)); 149 1.2 dyoung } 150 1.2 dyoung 151 1.2 dyoung /* 152 1.2 dyoung * Create or get top of sysctl tree net.link.ieee80211. 153 1.2 dyoung */ 154 1.2 dyoung static const struct sysctlnode * 155 1.2 dyoung ieee80211_sysctl_treetop(struct sysctllog **log) 156 1.2 dyoung { 157 1.2 dyoung int rc; 158 1.2 dyoung const struct sysctlnode *rnode; 159 1.1 dyoung 160 1.2 dyoung if ((rc = sysctl_createv(log, 0, NULL, &rnode, 161 1.2 dyoung CTLFLAG_PERMANENT, CTLTYPE_NODE, "link", 162 1.2 dyoung "link-layer statistics and controls", 163 1.25 pooka NULL, 0, NULL, 0, CTL_NET, PF_LINK, CTL_EOL)) != 0) 164 1.2 dyoung goto err; 165 1.2 dyoung 166 1.2 dyoung if ((rc = sysctl_createv(log, 0, &rnode, &rnode, 167 1.2 dyoung CTLFLAG_PERMANENT, CTLTYPE_NODE, "ieee80211", 168 1.2 dyoung "IEEE 802.11 WLAN statistics and controls", 169 1.2 dyoung NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0) 170 1.2 dyoung goto err; 171 1.2 dyoung 172 1.2 dyoung return rnode; 173 1.2 dyoung err: 174 1.2 dyoung printf("%s: sysctl_createv failed, rc = %d\n", __func__, rc); 175 1.2 dyoung return NULL; 176 1.1 dyoung } 177 1.1 dyoung 178 1.1 dyoung void 179 1.1 dyoung ieee80211_sysctl_attach(struct ieee80211com *ic) 180 1.1 dyoung { 181 1.2 dyoung int rc; 182 1.2 dyoung const struct sysctlnode *cnode, *rnode; 183 1.2 dyoung char num[sizeof("vap") + 14]; /* sufficient for 32 bits */ 184 1.2 dyoung 185 1.2 dyoung if ((rnode = ieee80211_sysctl_treetop(NULL)) == NULL) 186 1.1 dyoung return; 187 1.2 dyoung 188 1.2 dyoung snprintf(num, sizeof(num), "vap%u", ic->ic_vap); 189 1.2 dyoung 190 1.2 dyoung if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &rnode, 191 1.2 dyoung CTLFLAG_PERMANENT, CTLTYPE_NODE, num, SYSCTL_DESCR("virtual AP"), 192 1.2 dyoung NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0) 193 1.2 dyoung goto err; 194 1.2 dyoung 195 1.2 dyoung /* control debugging printfs */ 196 1.2 dyoung if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode, 197 1.2 dyoung CTLFLAG_PERMANENT|CTLFLAG_READONLY, CTLTYPE_STRING, 198 1.2 dyoung "parent", SYSCTL_DESCR("parent device"), 199 1.21 dsl ieee80211_sysctl_parent, 0, (void *)ic, IFNAMSIZ, CTL_CREATE, 200 1.2 dyoung CTL_EOL)) != 0) 201 1.2 dyoung goto err; 202 1.2 dyoung 203 1.1 dyoung #ifdef IEEE80211_DEBUG 204 1.2 dyoung /* control debugging printfs */ 205 1.2 dyoung if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode, 206 1.2 dyoung CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, 207 1.2 dyoung "debug", SYSCTL_DESCR("control debugging printfs"), 208 1.2 dyoung NULL, ieee80211_debug, &ic->ic_debug, 0, 209 1.2 dyoung CTL_CREATE, CTL_EOL)) != 0) 210 1.2 dyoung goto err; 211 1.1 dyoung #endif 212 1.1 dyoung /* XXX inherit from tunables */ 213 1.2 dyoung if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode, 214 1.2 dyoung CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, 215 1.2 dyoung "inact_run", SYSCTL_DESCR("station inactivity timeout (sec)"), 216 1.2 dyoung ieee80211_sysctl_inact, 0, &ic->ic_inact_run, 0, 217 1.2 dyoung CTL_CREATE, CTL_EOL)) != 0) 218 1.2 dyoung goto err; 219 1.2 dyoung if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode, 220 1.2 dyoung CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, 221 1.2 dyoung "inact_probe", 222 1.2 dyoung SYSCTL_DESCR("station inactivity probe timeout (sec)"), 223 1.2 dyoung ieee80211_sysctl_inact, 0, &ic->ic_inact_probe, 0, 224 1.2 dyoung CTL_CREATE, CTL_EOL)) != 0) 225 1.2 dyoung goto err; 226 1.2 dyoung if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode, 227 1.2 dyoung CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, 228 1.2 dyoung "inact_auth", 229 1.2 dyoung SYSCTL_DESCR("station authentication timeout (sec)"), 230 1.2 dyoung ieee80211_sysctl_inact, 0, &ic->ic_inact_auth, 0, 231 1.2 dyoung CTL_CREATE, CTL_EOL)) != 0) 232 1.2 dyoung goto err; 233 1.2 dyoung if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode, 234 1.2 dyoung CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, 235 1.2 dyoung "inact_init", 236 1.2 dyoung SYSCTL_DESCR("station initial state timeout (sec)"), 237 1.2 dyoung ieee80211_sysctl_inact, 0, &ic->ic_inact_init, 0, 238 1.2 dyoung CTL_CREATE, CTL_EOL)) != 0) 239 1.2 dyoung goto err; 240 1.2 dyoung if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode, 241 1.2 dyoung CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, 242 1.2 dyoung "driver_caps", SYSCTL_DESCR("driver capabilities"), 243 1.2 dyoung NULL, 0, &ic->ic_caps, 0, CTL_CREATE, CTL_EOL)) != 0) 244 1.2 dyoung goto err; 245 1.13 dyoung if ((rc = sysctl_createv(&ic->ic_sysctllog, 0, &rnode, &cnode, 246 1.13 dyoung CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, 247 1.13 dyoung "bmiss_max", SYSCTL_DESCR("consecutive beacon misses before scanning"), 248 1.13 dyoung NULL, 0, &ic->ic_bmiss_max, 0, CTL_CREATE, CTL_EOL)) != 0) 249 1.13 dyoung goto err; 250 1.2 dyoung 251 1.2 dyoung return; 252 1.2 dyoung err: 253 1.2 dyoung printf("%s: sysctl_createv failed, rc = %d\n", __func__, rc); 254 1.1 dyoung } 255 1.1 dyoung 256 1.1 dyoung void 257 1.1 dyoung ieee80211_sysctl_detach(struct ieee80211com *ic) 258 1.1 dyoung { 259 1.2 dyoung sysctl_teardown(&ic->ic_sysctllog); 260 1.2 dyoung } 261 1.2 dyoung 262 1.2 dyoung /* 263 1.2 dyoung * Pointers for testing: 264 1.2 dyoung * 265 1.2 dyoung * If there are no interfaces, or else no 802.11 interfaces, 266 1.2 dyoung * ieee80211_node_walkfirst must return NULL. 267 1.2 dyoung * 268 1.2 dyoung * If there is any single 802.11 interface, ieee80211_node_walkfirst 269 1.2 dyoung * must not return NULL. 270 1.30 maxv */ 271 1.2 dyoung static struct ieee80211_node * 272 1.3 dyoung ieee80211_node_walkfirst(struct ieee80211_node_walk *nw, u_short if_index) 273 1.2 dyoung { 274 1.30 maxv memset(nw, 0, sizeof(*nw)); 275 1.2 dyoung 276 1.2 dyoung nw->nw_ifindex = if_index; 277 1.2 dyoung 278 1.3 dyoung LIST_FOREACH(nw->nw_ic, &ieee80211com_head, ic_list) { 279 1.3 dyoung if (if_index != 0 && nw->nw_ic->ic_ifp->if_index != if_index) 280 1.3 dyoung continue; 281 1.3 dyoung if (!TAILQ_EMPTY(&nw->nw_ic->ic_sta.nt_node)) 282 1.3 dyoung nw->nw_nt = &nw->nw_ic->ic_sta; 283 1.3 dyoung else if (!TAILQ_EMPTY(&nw->nw_ic->ic_scan.nt_node)) 284 1.3 dyoung nw->nw_nt = &nw->nw_ic->ic_scan; 285 1.3 dyoung else if (nw->nw_ic->ic_bss == NULL) 286 1.2 dyoung continue; 287 1.2 dyoung break; 288 1.2 dyoung } 289 1.2 dyoung 290 1.3 dyoung if (nw->nw_ic == NULL) 291 1.3 dyoung return NULL; 292 1.3 dyoung 293 1.3 dyoung if (nw->nw_nt == NULL) 294 1.3 dyoung nw->nw_ni = nw->nw_ic->ic_bss; 295 1.3 dyoung else 296 1.3 dyoung nw->nw_ni = TAILQ_FIRST(&nw->nw_nt->nt_node); 297 1.2 dyoung 298 1.2 dyoung return nw->nw_ni; 299 1.2 dyoung } 300 1.2 dyoung 301 1.2 dyoung static struct ieee80211_node * 302 1.2 dyoung ieee80211_node_walknext(struct ieee80211_node_walk *nw) 303 1.2 dyoung { 304 1.3 dyoung if (nw->nw_nt != NULL) 305 1.3 dyoung nw->nw_ni = TAILQ_NEXT(nw->nw_ni, ni_list); 306 1.3 dyoung else 307 1.3 dyoung nw->nw_ni = NULL; 308 1.2 dyoung 309 1.3 dyoung while (nw->nw_ni == NULL) { 310 1.3 dyoung if (nw->nw_nt == &nw->nw_ic->ic_sta) { 311 1.3 dyoung nw->nw_nt = &nw->nw_ic->ic_scan; 312 1.3 dyoung nw->nw_ni = TAILQ_FIRST(&nw->nw_nt->nt_node); 313 1.3 dyoung continue; 314 1.3 dyoung } else if (nw->nw_nt == &nw->nw_ic->ic_scan) { 315 1.3 dyoung nw->nw_nt = NULL; 316 1.3 dyoung nw->nw_ni = nw->nw_ic->ic_bss; 317 1.3 dyoung continue; 318 1.3 dyoung } 319 1.3 dyoung KASSERT(nw->nw_nt == NULL); 320 1.2 dyoung if (nw->nw_ifindex != 0) 321 1.2 dyoung return NULL; 322 1.2 dyoung 323 1.2 dyoung nw->nw_ic = LIST_NEXT(nw->nw_ic, ic_list); 324 1.2 dyoung if (nw->nw_ic == NULL) 325 1.2 dyoung return NULL; 326 1.1 dyoung 327 1.3 dyoung nw->nw_nt = &nw->nw_ic->ic_sta; 328 1.3 dyoung nw->nw_ni = TAILQ_FIRST(&nw->nw_nt->nt_node); 329 1.2 dyoung } 330 1.2 dyoung 331 1.2 dyoung return nw->nw_ni; 332 1.2 dyoung } 333 1.2 dyoung 334 1.2 dyoung static void 335 1.2 dyoung ieee80211_sysctl_fill_node(struct ieee80211_node *ni, 336 1.2 dyoung struct ieee80211_node_sysctl *ns, int ifindex, 337 1.9 dyoung const struct ieee80211_channel *chan0, uint32_t flags) 338 1.2 dyoung { 339 1.30 maxv memset(ns, 0, sizeof(*ns)); 340 1.30 maxv 341 1.2 dyoung ns->ns_ifindex = ifindex; 342 1.2 dyoung ns->ns_capinfo = ni->ni_capinfo; 343 1.9 dyoung ns->ns_flags = flags; 344 1.30 maxv memcpy(ns->ns_macaddr, ni->ni_macaddr, sizeof(ns->ns_macaddr)); 345 1.30 maxv memcpy(ns->ns_bssid, ni->ni_bssid, sizeof(ns->ns_bssid)); 346 1.2 dyoung if (ni->ni_chan != IEEE80211_CHAN_ANYC) { 347 1.2 dyoung ns->ns_freq = ni->ni_chan->ic_freq; 348 1.2 dyoung ns->ns_chanflags = ni->ni_chan->ic_flags; 349 1.2 dyoung ns->ns_chanidx = ni->ni_chan - chan0; 350 1.2 dyoung } else { 351 1.2 dyoung ns->ns_freq = ns->ns_chanflags = 0; 352 1.2 dyoung ns->ns_chanidx = 0; 353 1.1 dyoung } 354 1.2 dyoung ns->ns_rssi = ni->ni_rssi; 355 1.2 dyoung ns->ns_esslen = ni->ni_esslen; 356 1.30 maxv memcpy(ns->ns_essid, ni->ni_essid, sizeof(ns->ns_essid)); 357 1.2 dyoung ns->ns_erp = ni->ni_erp; 358 1.2 dyoung ns->ns_associd = ni->ni_associd; 359 1.2 dyoung ns->ns_inact = ni->ni_inact * IEEE80211_INACT_WAIT; 360 1.2 dyoung ns->ns_rstamp = ni->ni_rstamp; 361 1.2 dyoung ns->ns_rates = ni->ni_rates; 362 1.2 dyoung ns->ns_txrate = ni->ni_txrate; 363 1.2 dyoung ns->ns_intval = ni->ni_intval; 364 1.30 maxv memcpy(ns->ns_tstamp, &ni->ni_tstamp, sizeof(ns->ns_tstamp)); 365 1.2 dyoung ns->ns_txseq = ni->ni_txseqs[0]; 366 1.2 dyoung ns->ns_rxseq = ni->ni_rxseqs[0]; 367 1.2 dyoung ns->ns_fhdwell = ni->ni_fhdwell; 368 1.2 dyoung ns->ns_fhindex = ni->ni_fhindex; 369 1.2 dyoung ns->ns_fails = ni->ni_fails; 370 1.2 dyoung } 371 1.2 dyoung 372 1.2 dyoung /* Between two examinations of the sysctl tree, I expect each 373 1.2 dyoung * interface to add no more than 5 nodes. 374 1.2 dyoung */ 375 1.2 dyoung #define IEEE80211_SYSCTL_NODE_GROWTH 5 376 1.2 dyoung 377 1.2 dyoung static int 378 1.2 dyoung ieee80211_sysctl_node(SYSCTLFN_ARGS) 379 1.2 dyoung { 380 1.2 dyoung struct ieee80211_node_walk nw; 381 1.2 dyoung struct ieee80211_node *ni; 382 1.2 dyoung struct ieee80211_node_sysctl ns; 383 1.2 dyoung char *dp; 384 1.2 dyoung u_int cur_ifindex, ifcount, ifindex, last_ifindex, op, arg, hdr_type; 385 1.9 dyoung uint32_t flags; 386 1.2 dyoung size_t len, needed, eltsize, out_size; 387 1.4 dyoung int error, s, saw_bss = 0, nelt; 388 1.2 dyoung 389 1.2 dyoung if (namelen == 1 && name[0] == CTL_QUERY) 390 1.2 dyoung return (sysctl_query(SYSCTLFN_CALL(rnode))); 391 1.2 dyoung 392 1.2 dyoung if (namelen != IEEE80211_SYSCTL_NODENAMELEN) 393 1.2 dyoung return (EINVAL); 394 1.2 dyoung 395 1.2 dyoung /* ifindex.op.arg.header-type.eltsize.nelt */ 396 1.2 dyoung dp = oldp; 397 1.2 dyoung len = (oldp != NULL) ? *oldlenp : 0; 398 1.2 dyoung ifindex = name[IEEE80211_SYSCTL_NODENAME_IF]; 399 1.2 dyoung op = name[IEEE80211_SYSCTL_NODENAME_OP]; 400 1.2 dyoung arg = name[IEEE80211_SYSCTL_NODENAME_ARG]; 401 1.2 dyoung hdr_type = name[IEEE80211_SYSCTL_NODENAME_TYPE]; 402 1.2 dyoung eltsize = name[IEEE80211_SYSCTL_NODENAME_ELTSIZE]; 403 1.2 dyoung nelt = name[IEEE80211_SYSCTL_NODENAME_ELTCOUNT]; 404 1.2 dyoung out_size = MIN(sizeof(ns), eltsize); 405 1.2 dyoung 406 1.2 dyoung if (op != IEEE80211_SYSCTL_OP_ALL || arg != 0 || 407 1.2 dyoung hdr_type != IEEE80211_SYSCTL_T_NODE || eltsize < 1 || nelt < 0) 408 1.2 dyoung return (EINVAL); 409 1.2 dyoung 410 1.2 dyoung error = 0; 411 1.2 dyoung needed = 0; 412 1.2 dyoung ifcount = 0; 413 1.2 dyoung last_ifindex = 0; 414 1.2 dyoung 415 1.2 dyoung s = splnet(); 416 1.2 dyoung 417 1.2 dyoung for (ni = ieee80211_node_walkfirst(&nw, ifindex); ni != NULL; 418 1.2 dyoung ni = ieee80211_node_walknext(&nw)) { 419 1.2 dyoung struct ieee80211com *ic; 420 1.2 dyoung 421 1.2 dyoung ic = nw.nw_ic; 422 1.2 dyoung cur_ifindex = ic->ic_ifp->if_index; 423 1.2 dyoung 424 1.2 dyoung if (cur_ifindex != last_ifindex) { 425 1.5 dyoung saw_bss = 0; 426 1.2 dyoung ifcount++; 427 1.2 dyoung last_ifindex = cur_ifindex; 428 1.2 dyoung } 429 1.2 dyoung 430 1.2 dyoung if (nelt <= 0) 431 1.2 dyoung continue; 432 1.2 dyoung 433 1.4 dyoung if (saw_bss && ni == ic->ic_bss) 434 1.4 dyoung continue; 435 1.9 dyoung else if (ni == ic->ic_bss) { 436 1.4 dyoung saw_bss = 1; 437 1.9 dyoung flags = IEEE80211_NODE_SYSCTL_F_BSS; 438 1.9 dyoung } else 439 1.9 dyoung flags = 0; 440 1.9 dyoung if (ni->ni_table == &ic->ic_scan) 441 1.9 dyoung flags |= IEEE80211_NODE_SYSCTL_F_SCAN; 442 1.9 dyoung else if (ni->ni_table == &ic->ic_sta) 443 1.9 dyoung flags |= IEEE80211_NODE_SYSCTL_F_STA; 444 1.2 dyoung if (len >= eltsize) { 445 1.2 dyoung ieee80211_sysctl_fill_node(ni, &ns, cur_ifindex, 446 1.9 dyoung &ic->ic_channels[0], flags); 447 1.2 dyoung error = copyout(&ns, dp, out_size); 448 1.2 dyoung if (error) 449 1.2 dyoung goto cleanup; 450 1.2 dyoung dp += eltsize; 451 1.2 dyoung len -= eltsize; 452 1.2 dyoung } 453 1.2 dyoung needed += eltsize; 454 1.2 dyoung if (nelt != INT_MAX) 455 1.2 dyoung nelt--; 456 1.2 dyoung } 457 1.2 dyoung cleanup: 458 1.2 dyoung splx(s); 459 1.2 dyoung 460 1.2 dyoung *oldlenp = needed; 461 1.2 dyoung if (oldp == NULL) 462 1.2 dyoung *oldlenp += ifcount * IEEE80211_SYSCTL_NODE_GROWTH * eltsize; 463 1.2 dyoung 464 1.2 dyoung return (error); 465 1.2 dyoung } 466 1.2 dyoung 467 1.2 dyoung /* 468 1.2 dyoung * Setup sysctl(3) MIB, net.ieee80211.* 469 1.2 dyoung * 470 1.17 ad * TBD condition CTLFLAG_PERMANENT on being a module or not 471 1.2 dyoung */ 472 1.26 pooka static struct sysctllog *ieee80211_sysctllog; 473 1.26 pooka static void 474 1.26 pooka ieee80211_sysctl_setup(void) 475 1.2 dyoung { 476 1.2 dyoung int rc; 477 1.28 christos const struct sysctlnode *rnode; 478 1.2 dyoung 479 1.26 pooka if ((rnode = ieee80211_sysctl_treetop(&ieee80211_sysctllog)) == NULL) 480 1.2 dyoung return; 481 1.2 dyoung 482 1.26 pooka if ((rc = sysctl_createv(&ieee80211_sysctllog, 0, &rnode, NULL, 483 1.2 dyoung CTLFLAG_PERMANENT, CTLTYPE_NODE, "nodes", "client/peer stations", 484 1.2 dyoung ieee80211_sysctl_node, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0) 485 1.2 dyoung goto err; 486 1.2 dyoung 487 1.2 dyoung #ifdef IEEE80211_DEBUG 488 1.2 dyoung /* control debugging printfs */ 489 1.28 christos if ((rc = sysctl_createv(&ieee80211_sysctllog, 0, &rnode, NULL, 490 1.2 dyoung CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, 491 1.2 dyoung "debug", SYSCTL_DESCR("control debugging printfs"), 492 1.2 dyoung NULL, 0, &ieee80211_debug, 0, CTL_CREATE, CTL_EOL)) != 0) 493 1.2 dyoung goto err; 494 1.30 maxv #endif 495 1.2 dyoung 496 1.26 pooka ieee80211_rssadapt_sysctl_setup(&ieee80211_sysctllog); 497 1.26 pooka 498 1.2 dyoung return; 499 1.2 dyoung err: 500 1.2 dyoung printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc); 501 1.1 dyoung } 502 1.1 dyoung 503 1.1 dyoung int 504 1.1 dyoung ieee80211_node_dectestref(struct ieee80211_node *ni) 505 1.1 dyoung { 506 1.19 dyoung if (atomic_dec_uint_nv(&ni->ni_refcnt) == 0) { 507 1.19 dyoung atomic_inc_uint(&ni->ni_refcnt); 508 1.19 dyoung return 1; 509 1.2 dyoung } else 510 1.19 dyoung return 0; 511 1.2 dyoung } 512 1.2 dyoung 513 1.2 dyoung void 514 1.15 degroote ieee80211_drain_ifq(struct ifqueue *ifq) 515 1.15 degroote { 516 1.15 degroote struct ieee80211_node *ni; 517 1.15 degroote struct mbuf *m; 518 1.15 degroote 519 1.15 degroote for (;;) { 520 1.15 degroote IF_DEQUEUE(ifq, m); 521 1.15 degroote if (m == NULL) 522 1.15 degroote break; 523 1.15 degroote 524 1.27 ozaki ni = M_GETCTX(m, struct ieee80211_node *); 525 1.15 degroote KASSERT(ni != NULL); 526 1.15 degroote ieee80211_free_node(ni); 527 1.27 ozaki M_SETCTX(m, NULL); 528 1.15 degroote 529 1.15 degroote m_freem(m); 530 1.15 degroote } 531 1.15 degroote } 532 1.15 degroote 533 1.15 degroote void 534 1.2 dyoung if_printf(struct ifnet *ifp, const char *fmt, ...) 535 1.2 dyoung { 536 1.2 dyoung va_list ap; 537 1.2 dyoung va_start(ap, fmt); 538 1.2 dyoung 539 1.2 dyoung printf("%s: ", ifp->if_xname); 540 1.2 dyoung vprintf(fmt, ap); 541 1.2 dyoung 542 1.2 dyoung va_end(ap); 543 1.2 dyoung return; 544 1.2 dyoung } 545 1.2 dyoung 546 1.1 dyoung /* 547 1.1 dyoung * Allocate and setup a management frame of the specified 548 1.1 dyoung * size. We return the mbuf and a pointer to the start 549 1.1 dyoung * of the contiguous data area that's been reserved based 550 1.1 dyoung * on the packet length. The data area is forced to 32-bit 551 1.1 dyoung * alignment and the buffer length to a multiple of 4 bytes. 552 1.1 dyoung * This is done mainly so beacon frames (that require this) 553 1.1 dyoung * can use this interface too. 554 1.1 dyoung */ 555 1.1 dyoung struct mbuf * 556 1.1 dyoung ieee80211_getmgtframe(u_int8_t **frm, u_int pktlen) 557 1.1 dyoung { 558 1.1 dyoung struct mbuf *m; 559 1.1 dyoung u_int len; 560 1.1 dyoung 561 1.1 dyoung /* 562 1.1 dyoung * NB: we know the mbuf routines will align the data area 563 1.1 dyoung * so we don't need to do anything special. 564 1.1 dyoung */ 565 1.1 dyoung /* XXX 4-address frame? */ 566 1.1 dyoung len = roundup(sizeof(struct ieee80211_frame) + pktlen, 4); 567 1.2 dyoung IASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len)); 568 1.30 maxv 569 1.2 dyoung if (len <= MHLEN) { 570 1.1 dyoung m = m_gethdr(M_NOWAIT, MT_HEADER); 571 1.1 dyoung /* 572 1.1 dyoung * Align the data in case additional headers are added. 573 1.1 dyoung * This should only happen when a WEP header is added 574 1.1 dyoung * which only happens for shared key authentication mgt 575 1.1 dyoung * frames which all fit in MHLEN. 576 1.1 dyoung */ 577 1.1 dyoung if (m != NULL) 578 1.34 maxv m_align(m, len); 579 1.30 maxv } else { 580 1.1 dyoung m = m_getcl(M_NOWAIT, MT_HEADER, M_PKTHDR); 581 1.30 maxv } 582 1.30 maxv 583 1.1 dyoung if (m != NULL) { 584 1.1 dyoung m->m_data += sizeof(struct ieee80211_frame); 585 1.1 dyoung *frm = m->m_data; 586 1.9 dyoung IASSERT((uintptr_t)*frm % 4 == 0, ("bad beacon boundary")); 587 1.1 dyoung } 588 1.30 maxv 589 1.1 dyoung return m; 590 1.1 dyoung } 591 1.1 dyoung 592 1.1 dyoung void 593 1.1 dyoung get_random_bytes(void *p, size_t n) 594 1.1 dyoung { 595 1.20 tls cprng_fast(p, n); 596 1.1 dyoung } 597 1.1 dyoung 598 1.1 dyoung void 599 1.30 maxv ieee80211_notify_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, 600 1.30 maxv int newassoc) 601 1.1 dyoung { 602 1.1 dyoung struct ifnet *ifp = ic->ic_ifp; 603 1.1 dyoung struct ieee80211_join_event iev; 604 1.1 dyoung 605 1.23 christos IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, "%snode %s join\n", 606 1.23 christos (ni == ic->ic_bss) ? "bss " : "", 607 1.3 dyoung ether_sprintf(ni->ni_macaddr)); 608 1.3 dyoung 609 1.7 dyoung memset(&iev, 0, sizeof(iev)); 610 1.1 dyoung if (ni == ic->ic_bss) { 611 1.1 dyoung IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_bssid); 612 1.1 dyoung rt_ieee80211msg(ifp, newassoc ? 613 1.30 maxv RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC, 614 1.30 maxv &iev, sizeof(iev)); 615 1.1 dyoung if_link_state_change(ifp, LINK_STATE_UP); 616 1.16 christos } else { 617 1.1 dyoung IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_macaddr); 618 1.16 christos rt_ieee80211msg(ifp, newassoc ? 619 1.16 christos RTM_IEEE80211_JOIN : RTM_IEEE80211_REJOIN, 620 1.16 christos &iev, sizeof(iev)); 621 1.1 dyoung } 622 1.1 dyoung } 623 1.1 dyoung 624 1.1 dyoung void 625 1.1 dyoung ieee80211_notify_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni) 626 1.1 dyoung { 627 1.1 dyoung struct ifnet *ifp = ic->ic_ifp; 628 1.1 dyoung struct ieee80211_leave_event iev; 629 1.1 dyoung 630 1.23 christos IEEE80211_DPRINTF(ic, IEEE80211_MSG_NODE, "%snode %s leave\n", 631 1.23 christos (ni == ic->ic_bss) ? "bss " : "", 632 1.3 dyoung ether_sprintf(ni->ni_macaddr)); 633 1.3 dyoung 634 1.1 dyoung if (ni == ic->ic_bss) { 635 1.1 dyoung rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0); 636 1.1 dyoung if_link_state_change(ifp, LINK_STATE_DOWN); 637 1.1 dyoung } else { 638 1.1 dyoung /* fire off wireless event station leaving */ 639 1.1 dyoung memset(&iev, 0, sizeof(iev)); 640 1.1 dyoung IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_macaddr); 641 1.1 dyoung rt_ieee80211msg(ifp, RTM_IEEE80211_LEAVE, &iev, sizeof(iev)); 642 1.1 dyoung } 643 1.1 dyoung } 644 1.1 dyoung 645 1.1 dyoung void 646 1.1 dyoung ieee80211_notify_scan_done(struct ieee80211com *ic) 647 1.1 dyoung { 648 1.1 dyoung struct ifnet *ifp = ic->ic_ifp; 649 1.1 dyoung 650 1.1 dyoung IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, 651 1.23 christos "%s", "notify scan done\n"); 652 1.1 dyoung 653 1.1 dyoung /* dispatch wireless event indicating scan completed */ 654 1.1 dyoung rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0); 655 1.1 dyoung } 656 1.1 dyoung 657 1.1 dyoung void 658 1.1 dyoung ieee80211_notify_replay_failure(struct ieee80211com *ic, 659 1.1 dyoung const struct ieee80211_frame *wh, const struct ieee80211_key *k, 660 1.1 dyoung u_int64_t rsc) 661 1.1 dyoung { 662 1.1 dyoung struct ifnet *ifp = ic->ic_ifp; 663 1.1 dyoung 664 1.1 dyoung IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 665 1.8 skrll "[%s] %s replay detected <rsc %ju, csc %ju, keyix %u rxkeyix %u>\n", 666 1.8 skrll ether_sprintf(wh->i_addr2), k->wk_cipher->ic_name, 667 1.8 skrll (intmax_t) rsc, (intmax_t) k->wk_keyrsc, 668 1.8 skrll k->wk_keyix, k->wk_rxkeyix); 669 1.1 dyoung 670 1.1 dyoung if (ifp != NULL) { /* NB: for cipher test modules */ 671 1.1 dyoung struct ieee80211_replay_event iev; 672 1.1 dyoung 673 1.1 dyoung IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); 674 1.1 dyoung IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); 675 1.1 dyoung iev.iev_cipher = k->wk_cipher->ic_cipher; 676 1.8 skrll if (k->wk_rxkeyix != IEEE80211_KEYIX_NONE) 677 1.8 skrll iev.iev_keyix = k->wk_rxkeyix; 678 1.8 skrll else 679 1.8 skrll iev.iev_keyix = k->wk_keyix; 680 1.1 dyoung iev.iev_keyrsc = k->wk_keyrsc; 681 1.1 dyoung iev.iev_rsc = rsc; 682 1.1 dyoung rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev)); 683 1.1 dyoung } 684 1.1 dyoung } 685 1.1 dyoung 686 1.1 dyoung void 687 1.1 dyoung ieee80211_notify_michael_failure(struct ieee80211com *ic, 688 1.1 dyoung const struct ieee80211_frame *wh, u_int keyix) 689 1.1 dyoung { 690 1.1 dyoung struct ifnet *ifp = ic->ic_ifp; 691 1.1 dyoung 692 1.1 dyoung IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 693 1.30 maxv "[%s] michael MIC verification failed <keyix %u>\n", 694 1.30 maxv ether_sprintf(wh->i_addr2), keyix); 695 1.1 dyoung ic->ic_stats.is_rx_tkipmic++; 696 1.1 dyoung 697 1.1 dyoung if (ifp != NULL) { /* NB: for cipher test modules */ 698 1.1 dyoung struct ieee80211_michael_event iev; 699 1.1 dyoung 700 1.1 dyoung IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); 701 1.1 dyoung IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); 702 1.1 dyoung iev.iev_cipher = IEEE80211_CIPHER_TKIP; 703 1.1 dyoung iev.iev_keyix = keyix; 704 1.1 dyoung rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev)); 705 1.1 dyoung } 706 1.1 dyoung } 707 1.1 dyoung 708 1.1 dyoung void 709 1.1 dyoung ieee80211_load_module(const char *modname) 710 1.1 dyoung { 711 1.1 dyoung #ifdef notyet 712 1.1 dyoung struct thread *td = curthread; 713 1.1 dyoung 714 1.1 dyoung if (suser(td) == 0 && securelevel_gt(td->td_ucred, 0) == 0) { 715 1.1 dyoung mtx_lock(&Giant); 716 1.1 dyoung (void) linker_load_module(modname, NULL, NULL, NULL, NULL); 717 1.1 dyoung mtx_unlock(&Giant); 718 1.1 dyoung } 719 1.1 dyoung #else 720 1.1 dyoung printf("%s: load the %s module by hand for now.\n", __func__, modname); 721 1.1 dyoung #endif 722 1.1 dyoung } 723 1.31 maxv 724 1.31 maxv /* -------------------------------------------------------------------------- */ 725 1.31 maxv 726 1.31 maxv /* 727 1.31 maxv * Append the specified data to the indicated mbuf chain, 728 1.31 maxv * Extend the mbuf chain if the new data does not fit in 729 1.31 maxv * existing space. 730 1.31 maxv * 731 1.31 maxv * Return 1 if able to complete the job; otherwise 0. 732 1.31 maxv */ 733 1.31 maxv int 734 1.31 maxv m_append(struct mbuf *m0, int len, const void *cpv) 735 1.31 maxv { 736 1.31 maxv struct mbuf *m, *n; 737 1.31 maxv int remainder, space; 738 1.31 maxv const char *cp = cpv; 739 1.31 maxv 740 1.31 maxv KASSERT(len != M_COPYALL); 741 1.31 maxv for (m = m0; m->m_next != NULL; m = m->m_next) 742 1.31 maxv continue; 743 1.31 maxv remainder = len; 744 1.31 maxv space = M_TRAILINGSPACE(m); 745 1.31 maxv if (space > 0) { 746 1.31 maxv /* 747 1.31 maxv * Copy into available space. 748 1.31 maxv */ 749 1.31 maxv if (space > remainder) 750 1.31 maxv space = remainder; 751 1.31 maxv memmove(mtod(m, char *) + m->m_len, cp, space); 752 1.31 maxv m->m_len += space; 753 1.31 maxv cp = cp + space, remainder -= space; 754 1.31 maxv } 755 1.31 maxv while (remainder > 0) { 756 1.31 maxv /* 757 1.31 maxv * Allocate a new mbuf; could check space 758 1.31 maxv * and allocate a cluster instead. 759 1.31 maxv */ 760 1.31 maxv n = m_get(M_DONTWAIT, m->m_type); 761 1.31 maxv if (n == NULL) 762 1.31 maxv break; 763 1.32 riastrad n->m_len = uimin(MLEN, remainder); 764 1.31 maxv memmove(mtod(n, void *), cp, n->m_len); 765 1.31 maxv cp += n->m_len, remainder -= n->m_len; 766 1.31 maxv m->m_next = n; 767 1.31 maxv m = n; 768 1.31 maxv } 769 1.31 maxv if (m0->m_flags & M_PKTHDR) 770 1.31 maxv m0->m_pkthdr.len += len - remainder; 771 1.31 maxv return (remainder == 0); 772 1.31 maxv } 773