ieee80211_adhoc.c revision 178354
1266072Sdes/*- 2266072Sdes * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting 3266072Sdes * All rights reserved. 4266072Sdes * 5266072Sdes * Redistribution and use in source and binary forms, with or without 6266072Sdes * modification, are permitted provided that the following conditions 7266072Sdes * are met: 8266072Sdes * 1. Redistributions of source code must retain the above copyright 9266072Sdes * notice, this list of conditions and the following disclaimer. 10266072Sdes * 2. Redistributions in binary form must reproduce the above copyright 11266072Sdes * notice, this list of conditions and the following disclaimer in the 12266072Sdes * documentation and/or other materials provided with the distribution. 13266072Sdes * 14266072Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15266072Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16266072Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17266072Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18266072Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19266072Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20266072Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21266072Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22266072Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23266072Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24266072Sdes */ 25266072Sdes 26266072Sdes#include <sys/cdefs.h> 27266072Sdes#ifdef __FreeBSD__ 28266072Sdes__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_adhoc.c 178354 2008-04-20 20:35:46Z sam $"); 29266072Sdes#endif 30266072Sdes 31266072Sdes/* 32266072Sdes * IEEE 802.11 IBSS mode support. 33266072Sdes */ 34266072Sdes#include "opt_inet.h" 35266072Sdes#include "opt_wlan.h" 36266072Sdes 37266072Sdes#include <sys/param.h> 38266072Sdes#include <sys/systm.h> 39266072Sdes#include <sys/mbuf.h> 40266072Sdes#include <sys/malloc.h> 41266072Sdes#include <sys/kernel.h> 42266072Sdes 43266072Sdes#include <sys/socket.h> 44266072Sdes#include <sys/sockio.h> 45266072Sdes#include <sys/endian.h> 46266072Sdes#include <sys/errno.h> 47266072Sdes#include <sys/proc.h> 48266072Sdes#include <sys/sysctl.h> 49266072Sdes 50266072Sdes#include <net/if.h> 51266072Sdes#include <net/if_media.h> 52266072Sdes#include <net/if_llc.h> 53266072Sdes#include <net/ethernet.h> 54266072Sdes 55266072Sdes#include <net/bpf.h> 56266072Sdes 57266072Sdes#include <net80211/ieee80211_var.h> 58266072Sdes#include <net80211/ieee80211_adhoc.h> 59266072Sdes#include <net80211/ieee80211_input.h> 60266072Sdes 61266072Sdes#define IEEE80211_RATE2MBS(r) (((r) & IEEE80211_RATE_VAL) / 2) 62266072Sdes 63266072Sdesstatic void adhoc_vattach(struct ieee80211vap *); 64266072Sdesstatic int adhoc_newstate(struct ieee80211vap *, enum ieee80211_state, int); 65266072Sdesstatic int adhoc_input(struct ieee80211_node *, struct mbuf *, 66266072Sdes int rssi, int noise, uint32_t rstamp); 67266072Sdesstatic void adhoc_recv_mgmt(struct ieee80211_node *, struct mbuf *, 68266072Sdes int subtype, int rssi, int noise, uint32_t rstamp); 69266072Sdes 70266072Sdesvoid 71266072Sdesieee80211_adhoc_attach(struct ieee80211com *ic) 72266072Sdes{ 73266072Sdes ic->ic_vattach[IEEE80211_M_IBSS] = adhoc_vattach; 74266072Sdes ic->ic_vattach[IEEE80211_M_AHDEMO] = adhoc_vattach; 75266072Sdes} 76266072Sdes 77266072Sdesvoid 78266072Sdesieee80211_adhoc_detach(struct ieee80211com *ic) 79266072Sdes{ 80266072Sdes} 81266072Sdes 82266072Sdesstatic void 83266072Sdesadhoc_vdetach(struct ieee80211vap *vap) 84266072Sdes{ 85266072Sdes} 86266072Sdes 87266072Sdesstatic void 88266072Sdesadhoc_vattach(struct ieee80211vap *vap) 89266072Sdes{ 90266072Sdes vap->iv_newstate = adhoc_newstate; 91266072Sdes vap->iv_input = adhoc_input; 92266072Sdes vap->iv_recv_mgmt = adhoc_recv_mgmt; 93266072Sdes vap->iv_opdetach = adhoc_vdetach; 94266072Sdes} 95266072Sdes 96266072Sdes/* 97266072Sdes * IEEE80211_M_IBSS+IEEE80211_M_AHDEMO vap state machine handler. 98266072Sdes */ 99266072Sdesstatic int 100266072Sdesadhoc_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg) 101266072Sdes{ 102266072Sdes#ifdef IEEE80211_DEBUG 103266072Sdes struct ieee80211com *ic = vap->iv_ic; 104266072Sdes#endif 105266072Sdes struct ieee80211_node *ni; 106266072Sdes enum ieee80211_state ostate; 107266072Sdes 108266072Sdes IEEE80211_LOCK_ASSERT(vap->iv_ic); 109266072Sdes 110266072Sdes ostate = vap->iv_state; 111266072Sdes IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE, "%s: %s -> %s (%d)\n", 112266072Sdes __func__, ieee80211_state_name[ostate], 113266072Sdes ieee80211_state_name[nstate], arg); 114266072Sdes vap->iv_state = nstate; /* state transition */ 115266072Sdes if (ostate != IEEE80211_S_SCAN) 116266072Sdes ieee80211_cancel_scan(vap); /* background scan */ 117266072Sdes ni = vap->iv_bss; /* NB: no reference held */ 118266072Sdes if (vap->iv_flags_ext & IEEE80211_FEXT_SWBMISS) 119266072Sdes callout_stop(&vap->iv_swbmiss); 120266072Sdes switch (nstate) { 121266072Sdes case IEEE80211_S_INIT: 122266072Sdes switch (ostate) { 123266072Sdes case IEEE80211_S_SCAN: 124266072Sdes ieee80211_cancel_scan(vap); 125266072Sdes break; 126266072Sdes default: 127266072Sdes break; 128266072Sdes } 129266072Sdes if (ostate != IEEE80211_S_INIT) { 130266072Sdes /* NB: optimize INIT -> INIT case */ 131266072Sdes ieee80211_reset_bss(vap); 132266072Sdes } 133266072Sdes break; 134266072Sdes case IEEE80211_S_SCAN: 135266072Sdes switch (ostate) { 136266072Sdes case IEEE80211_S_INIT: 137266072Sdes case IEEE80211_S_RUN: /* beacon miss */ 138266072Sdes if (vap->iv_des_chan != IEEE80211_CHAN_ANYC && 139266072Sdes !IEEE80211_IS_CHAN_RADAR(vap->iv_des_chan)) { 140266072Sdes /* 141266072Sdes * Already have a channel; bypass the 142266072Sdes * scan and startup immediately. 143266072Sdes */ 144266072Sdes ieee80211_create_ibss(vap, vap->iv_des_chan); 145266072Sdes break; 146266072Sdes } 147266072Sdes /* 148266072Sdes * Initiate a scan. We can come here as a result 149266072Sdes * of an IEEE80211_IOC_SCAN_REQ too in which case 150266072Sdes * the vap will be marked with IEEE80211_FEXT_SCANREQ 151266072Sdes * and the scan request parameters will be present 152266072Sdes * in iv_scanreq. Otherwise we do the default. 153266072Sdes */ 154266072Sdes if (vap->iv_flags_ext & IEEE80211_FEXT_SCANREQ) { 155266072Sdes ieee80211_check_scan(vap, 156266072Sdes vap->iv_scanreq_flags, 157266072Sdes vap->iv_scanreq_duration, 158266072Sdes vap->iv_scanreq_mindwell, 159266072Sdes vap->iv_scanreq_maxdwell, 160266072Sdes vap->iv_scanreq_nssid, vap->iv_scanreq_ssid); 161266072Sdes vap->iv_flags_ext &= ~IEEE80211_FEXT_SCANREQ; 162266072Sdes } else 163266072Sdes ieee80211_check_scan_current(vap); 164266072Sdes break; 165266072Sdes case IEEE80211_S_SCAN: 166266072Sdes /* 167266072Sdes * This can happen because of a change in state 168266072Sdes * that requires a reset. Trigger a new scan 169266072Sdes * unless we're in manual roaming mode in which 170266072Sdes * case an application must issue an explicit request. 171266072Sdes */ 172266072Sdes if (vap->iv_roaming == IEEE80211_ROAMING_AUTO) 173266072Sdes ieee80211_check_scan_current(vap); 174266072Sdes break; 175266072Sdes default: 176266072Sdes goto invalid; 177266072Sdes } 178266072Sdes break; 179266072Sdes case IEEE80211_S_RUN: 180266072Sdes if (vap->iv_flags & IEEE80211_F_WPA) { 181266072Sdes /* XXX validate prerequisites */ 182266072Sdes } 183266072Sdes switch (ostate) { 184266072Sdes case IEEE80211_S_SCAN: 185266072Sdes#ifdef IEEE80211_DEBUG 186266072Sdes if (ieee80211_msg_debug(vap)) { 187266072Sdes ieee80211_note(vap, 188266072Sdes "synchronized with %s ssid ", 189266072Sdes ether_sprintf(ni->ni_bssid)); 190266072Sdes ieee80211_print_essid(vap->iv_bss->ni_essid, 191266072Sdes ni->ni_esslen); 192266072Sdes /* XXX MCS/HT */ 193266072Sdes printf(" channel %d start %uMb\n", 194266072Sdes ieee80211_chan2ieee(ic, ic->ic_curchan), 195266072Sdes IEEE80211_RATE2MBS(ni->ni_txrate)); 196266072Sdes } 197266072Sdes#endif 198266072Sdes break; 199266072Sdes default: 200266072Sdes goto invalid; 201266072Sdes } 202266072Sdes /* 203266072Sdes * When 802.1x is not in use mark the port authorized 204266072Sdes * at this point so traffic can flow. 205266072Sdes */ 206266072Sdes if (ni->ni_authmode != IEEE80211_AUTH_8021X) 207266072Sdes ieee80211_node_authorize(ni); 208266072Sdes break; 209266072Sdes case IEEE80211_S_SLEEP: 210266072Sdes ieee80211_sta_pwrsave(vap, 0); 211266072Sdes break; 212266072Sdes default: 213266072Sdes invalid: 214266072Sdes IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY, 215266072Sdes "%s: invalid state transition %s -> %s\n", __func__, 216266072Sdes ieee80211_state_name[ostate], ieee80211_state_name[nstate]); 217266072Sdes break; 218266072Sdes } 219266072Sdes return 0; 220266072Sdes} 221266072Sdes 222266072Sdes/* 223266072Sdes * Decide if a received management frame should be 224266072Sdes * printed when debugging is enabled. This filters some 225266072Sdes * of the less interesting frames that come frequently 226266072Sdes * (e.g. beacons). 227266072Sdes */ 228266072Sdesstatic __inline int 229266072Sdesdoprint(struct ieee80211vap *vap, int subtype) 230266072Sdes{ 231266072Sdes switch (subtype) { 232266072Sdes case IEEE80211_FC0_SUBTYPE_BEACON: 233266072Sdes return (vap->iv_ic->ic_flags & IEEE80211_F_SCAN); 234266072Sdes case IEEE80211_FC0_SUBTYPE_PROBE_REQ: 235266072Sdes return 1; 236266072Sdes } 237266072Sdes return 1; 238266072Sdes} 239266072Sdes 240266072Sdes/* 241266072Sdes * Process a received frame. The node associated with the sender 242266072Sdes * should be supplied. If nothing was found in the node table then 243266072Sdes * the caller is assumed to supply a reference to iv_bss instead. 244266072Sdes * The RSSI and a timestamp are also supplied. The RSSI data is used 245266072Sdes * during AP scanning to select a AP to associate with; it can have 246266072Sdes * any units so long as values have consistent units and higher values 247266072Sdes * mean ``better signal''. The receive timestamp is currently not used 248266072Sdes * by the 802.11 layer. 249266072Sdes */ 250266072Sdesstatic int 251266072Sdesadhoc_input(struct ieee80211_node *ni, struct mbuf *m, 252266072Sdes int rssi, int noise, uint32_t rstamp) 253266072Sdes{ 254266072Sdes#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) 255266072Sdes#define HAS_SEQ(type) ((type & 0x4) == 0) 256266072Sdes struct ieee80211vap *vap = ni->ni_vap; 257266072Sdes struct ieee80211com *ic = ni->ni_ic; 258266072Sdes struct ifnet *ifp = vap->iv_ifp; 259266072Sdes struct ieee80211_frame *wh; 260266072Sdes struct ieee80211_key *key; 261266072Sdes struct ether_header *eh; 262266072Sdes int hdrspace, need_tap; 263266072Sdes uint8_t dir, type, subtype, qos; 264266072Sdes uint8_t *bssid; 265266072Sdes uint16_t rxseq; 266266072Sdes 267266072Sdes if (m->m_flags & M_AMPDU) { 268266072Sdes /* 269266072Sdes * Fastpath for A-MPDU reorder q resubmission. Frames 270266072Sdes * w/ M_AMPDU marked have already passed through here 271266072Sdes * but were received out of order and been held on the 272266072Sdes * reorder queue. When resubmitted they are marked 273266072Sdes * with the M_AMPDU flag and we can bypass most of the 274266072Sdes * normal processing. 275266072Sdes */ 276266072Sdes wh = mtod(m, struct ieee80211_frame *); 277266072Sdes type = IEEE80211_FC0_TYPE_DATA; 278266072Sdes dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; 279266072Sdes subtype = IEEE80211_FC0_SUBTYPE_QOS; 280266072Sdes hdrspace = ieee80211_hdrspace(ic, wh); /* XXX optimize? */ 281266072Sdes goto resubmit_ampdu; 282266072Sdes } 283266072Sdes 284266072Sdes KASSERT(ni != NULL, ("null node")); 285266072Sdes ni->ni_inact = ni->ni_inact_reload; 286266072Sdes 287266072Sdes need_tap = 1; /* mbuf need to be tapped. */ 288266072Sdes type = -1; /* undefined */ 289266072Sdes 290266072Sdes if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min)) { 291266072Sdes IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, 292266072Sdes ni->ni_macaddr, NULL, 293266072Sdes "too short (1): len %u", m->m_pkthdr.len); 294266072Sdes vap->iv_stats.is_rx_tooshort++; 295266072Sdes goto out; 296266072Sdes } 297266072Sdes /* 298266072Sdes * Bit of a cheat here, we use a pointer for a 3-address 299266072Sdes * frame format but don't reference fields past outside 300266072Sdes * ieee80211_frame_min w/o first validating the data is 301266072Sdes * present. 302266072Sdes */ 303266072Sdes wh = mtod(m, struct ieee80211_frame *); 304266072Sdes 305266072Sdes if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != 306266072Sdes IEEE80211_FC0_VERSION_0) { 307266072Sdes IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, 308266072Sdes ni->ni_macaddr, NULL, "wrong version %x", wh->i_fc[0]); 309266072Sdes vap->iv_stats.is_rx_badversion++; 310266072Sdes goto err; 311266072Sdes } 312266072Sdes 313266072Sdes dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK; 314266072Sdes type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 315266072Sdes subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 316266072Sdes if ((ic->ic_flags & IEEE80211_F_SCAN) == 0) { 317266072Sdes if (dir != IEEE80211_FC1_DIR_NODS) 318266072Sdes bssid = wh->i_addr1; 319266072Sdes else if (type == IEEE80211_FC0_TYPE_CTL) 320266072Sdes bssid = wh->i_addr1; 321266072Sdes else { 322266072Sdes if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) { 323266072Sdes IEEE80211_DISCARD_MAC(vap, 324266072Sdes IEEE80211_MSG_ANY, ni->ni_macaddr, 325266072Sdes NULL, "too short (2): len %u", 326266072Sdes m->m_pkthdr.len); 327266072Sdes vap->iv_stats.is_rx_tooshort++; 328266072Sdes goto out; 329266072Sdes } 330266072Sdes bssid = wh->i_addr3; 331266072Sdes } 332266072Sdes /* 333266072Sdes * Validate the bssid. 334266072Sdes */ 335266072Sdes if (!IEEE80211_ADDR_EQ(bssid, vap->iv_bss->ni_bssid) && 336266072Sdes !IEEE80211_ADDR_EQ(bssid, ifp->if_broadcastaddr)) { 337266072Sdes /* not interested in */ 338266072Sdes IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, 339266072Sdes bssid, NULL, "%s", "not to bss"); 340266072Sdes vap->iv_stats.is_rx_wrongbss++; 341266072Sdes goto out; 342266072Sdes } 343266072Sdes /* 344266072Sdes * Data frame, cons up a node when it doesn't 345266072Sdes * exist. This should probably done after an ACL check. 346266072Sdes */ 347266072Sdes if (type == IEEE80211_FC0_TYPE_DATA && 348266072Sdes ni == vap->iv_bss && 349266072Sdes !IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) { 350266072Sdes /* 351266072Sdes * Fake up a node for this newly 352266072Sdes * discovered member of the IBSS. 353266072Sdes */ 354266072Sdes ni = ieee80211_fakeup_adhoc_node(vap, wh->i_addr2); 355266072Sdes if (ni == NULL) { 356266072Sdes /* NB: stat kept for alloc failure */ 357266072Sdes goto err; 358266072Sdes } 359266072Sdes } 360266072Sdes IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi); 361266072Sdes ni->ni_noise = noise; 362266072Sdes ni->ni_rstamp = rstamp; 363266072Sdes if (HAS_SEQ(type)) { 364266072Sdes uint8_t tid = ieee80211_gettid(wh); 365266072Sdes if (IEEE80211_QOS_HAS_SEQ(wh) && 366266072Sdes TID_TO_WME_AC(tid) >= WME_AC_VI) 367266072Sdes ic->ic_wme.wme_hipri_traffic++; 368266072Sdes rxseq = le16toh(*(uint16_t *)wh->i_seq); 369266072Sdes if ((ni->ni_flags & IEEE80211_NODE_HT) == 0 && 370266072Sdes (wh->i_fc[1] & IEEE80211_FC1_RETRY) && 371266072Sdes SEQ_LEQ(rxseq, ni->ni_rxseqs[tid])) { 372266072Sdes /* duplicate, discard */ 373266072Sdes IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, 374266072Sdes bssid, "duplicate", 375266072Sdes "seqno <%u,%u> fragno <%u,%u> tid %u", 376266072Sdes rxseq >> IEEE80211_SEQ_SEQ_SHIFT, 377266072Sdes ni->ni_rxseqs[tid] >> 378266072Sdes IEEE80211_SEQ_SEQ_SHIFT, 379266072Sdes rxseq & IEEE80211_SEQ_FRAG_MASK, 380266072Sdes ni->ni_rxseqs[tid] & 381266072Sdes IEEE80211_SEQ_FRAG_MASK, 382266072Sdes tid); 383266072Sdes vap->iv_stats.is_rx_dup++; 384266072Sdes IEEE80211_NODE_STAT(ni, rx_dup); 385266072Sdes goto out; 386266072Sdes } 387266072Sdes ni->ni_rxseqs[tid] = rxseq; 388266072Sdes } 389266072Sdes } 390266072Sdes 391266072Sdes switch (type) { 392266072Sdes case IEEE80211_FC0_TYPE_DATA: 393266072Sdes hdrspace = ieee80211_hdrspace(ic, wh); 394266072Sdes if (m->m_len < hdrspace && 395266072Sdes (m = m_pullup(m, hdrspace)) == NULL) { 396266072Sdes IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, 397266072Sdes ni->ni_macaddr, NULL, 398266072Sdes "data too short: expecting %u", hdrspace); 399266072Sdes vap->iv_stats.is_rx_tooshort++; 400266072Sdes goto out; /* XXX */ 401266072Sdes } 402266072Sdes if (dir != IEEE80211_FC1_DIR_NODS) { 403266072Sdes IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, 404266072Sdes wh, "data", "incorrect dir 0x%x", dir); 405266072Sdes vap->iv_stats.is_rx_wrongdir++; 406266072Sdes goto out; 407266072Sdes } 408266072Sdes /* XXX no power-save support */ 409266072Sdes 410266072Sdes /* 411266072Sdes * Handle A-MPDU re-ordering. The station must be 412266072Sdes * associated and negotiated HT. The frame must be 413266072Sdes * a QoS frame (not QoS null data) and not previously 414266072Sdes * processed for A-MPDU re-ordering. If the frame is 415266072Sdes * to be processed directly then ieee80211_ampdu_reorder 416266072Sdes * will return 0; otherwise it has consumed the mbuf 417266072Sdes * and we should do nothing more with it. 418266072Sdes */ 419266072Sdes if ((ni->ni_flags & IEEE80211_NODE_HT) && 420266072Sdes subtype == IEEE80211_FC0_SUBTYPE_QOS && 421266072Sdes ieee80211_ampdu_reorder(ni, m) != 0) { 422266072Sdes m = NULL; 423266072Sdes goto out; 424266072Sdes } 425266072Sdes resubmit_ampdu: 426266072Sdes 427266072Sdes /* 428266072Sdes * Handle privacy requirements. Note that we 429266072Sdes * must not be preempted from here until after 430266072Sdes * we (potentially) call ieee80211_crypto_demic; 431266072Sdes * otherwise we may violate assumptions in the 432266072Sdes * crypto cipher modules used to do delayed update 433266072Sdes * of replay sequence numbers. 434266072Sdes */ 435266072Sdes if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 436266072Sdes if ((vap->iv_flags & IEEE80211_F_PRIVACY) == 0) { 437266072Sdes /* 438266072Sdes * Discard encrypted frames when privacy is off. 439266072Sdes */ 440266072Sdes IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, 441266072Sdes wh, "WEP", "%s", "PRIVACY off"); 442266072Sdes vap->iv_stats.is_rx_noprivacy++; 443266072Sdes IEEE80211_NODE_STAT(ni, rx_noprivacy); 444266072Sdes goto out; 445266072Sdes } 446266072Sdes key = ieee80211_crypto_decap(ni, m, hdrspace); 447266072Sdes if (key == NULL) { 448266072Sdes /* NB: stats+msgs handled in crypto_decap */ 449266072Sdes IEEE80211_NODE_STAT(ni, rx_wepfail); 450266072Sdes goto out; 451266072Sdes } 452266072Sdes wh = mtod(m, struct ieee80211_frame *); 453266072Sdes wh->i_fc[1] &= ~IEEE80211_FC1_WEP; 454266072Sdes } else { 455266072Sdes /* XXX M_WEP and IEEE80211_F_PRIVACY */ 456266072Sdes key = NULL; 457266072Sdes } 458266072Sdes 459266072Sdes /* 460266072Sdes * Save QoS bits for use below--before we strip the header. 461266072Sdes */ 462266072Sdes if (subtype == IEEE80211_FC0_SUBTYPE_QOS) { 463266072Sdes qos = (dir == IEEE80211_FC1_DIR_DSTODS) ? 464266072Sdes ((struct ieee80211_qosframe_addr4 *)wh)->i_qos[0] : 465266072Sdes ((struct ieee80211_qosframe *)wh)->i_qos[0]; 466266072Sdes } else 467266072Sdes qos = 0; 468266072Sdes 469266072Sdes /* 470266072Sdes * Next up, any fragmentation. 471266072Sdes */ 472266072Sdes if (!IEEE80211_IS_MULTICAST(wh->i_addr1)) { 473266072Sdes m = ieee80211_defrag(ni, m, hdrspace); 474266072Sdes if (m == NULL) { 475266072Sdes /* Fragment dropped or frame not complete yet */ 476266072Sdes goto out; 477266072Sdes } 478266072Sdes } 479266072Sdes wh = NULL; /* no longer valid, catch any uses */ 480266072Sdes 481266072Sdes /* 482266072Sdes * Next strip any MSDU crypto bits. 483266072Sdes */ 484266072Sdes if (key != NULL && !ieee80211_crypto_demic(vap, key, m, 0)) { 485266072Sdes IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, 486266072Sdes ni->ni_macaddr, "data", "%s", "demic error"); 487266072Sdes vap->iv_stats.is_rx_demicfail++; 488266072Sdes IEEE80211_NODE_STAT(ni, rx_demicfail); 489266072Sdes goto out; 490266072Sdes } 491266072Sdes 492266072Sdes /* copy to listener after decrypt */ 493266072Sdes if (bpf_peers_present(vap->iv_rawbpf)) 494266072Sdes bpf_mtap(vap->iv_rawbpf, m); 495266072Sdes need_tap = 0; 496266072Sdes 497266072Sdes /* 498266072Sdes * Finally, strip the 802.11 header. 499266072Sdes */ 500266072Sdes m = ieee80211_decap(vap, m, hdrspace); 501266072Sdes if (m == NULL) { 502266072Sdes /* XXX mask bit to check for both */ 503266072Sdes /* don't count Null data frames as errors */ 504266072Sdes if (subtype == IEEE80211_FC0_SUBTYPE_NODATA || 505266072Sdes subtype == IEEE80211_FC0_SUBTYPE_QOS_NULL) 506266072Sdes goto out; 507266072Sdes IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, 508266072Sdes ni->ni_macaddr, "data", "%s", "decap error"); 509266072Sdes vap->iv_stats.is_rx_decap++; 510266072Sdes IEEE80211_NODE_STAT(ni, rx_decap); 511266072Sdes goto err; 512266072Sdes } 513266072Sdes eh = mtod(m, struct ether_header *); 514266072Sdes if (!ieee80211_node_is_authorized(ni)) { 515266072Sdes /* 516266072Sdes * Deny any non-PAE frames received prior to 517266072Sdes * authorization. For open/shared-key 518266072Sdes * authentication the port is mark authorized 519266072Sdes * after authentication completes. For 802.1x 520266072Sdes * the port is not marked authorized by the 521266072Sdes * authenticator until the handshake has completed. 522266072Sdes */ 523266072Sdes if (eh->ether_type != htons(ETHERTYPE_PAE)) { 524266072Sdes IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT, 525266072Sdes eh->ether_shost, "data", 526266072Sdes "unauthorized port: ether type 0x%x len %u", 527266072Sdes eh->ether_type, m->m_pkthdr.len); 528266072Sdes vap->iv_stats.is_rx_unauth++; 529266072Sdes IEEE80211_NODE_STAT(ni, rx_unauth); 530266072Sdes goto err; 531266072Sdes } 532266072Sdes } else { 533266072Sdes /* 534266072Sdes * When denying unencrypted frames, discard 535266072Sdes * any non-PAE frames received without encryption. 536266072Sdes */ 537266072Sdes if ((vap->iv_flags & IEEE80211_F_DROPUNENC) && 538266072Sdes (key == NULL && (m->m_flags & M_WEP) == 0) && 539266072Sdes eh->ether_type != htons(ETHERTYPE_PAE)) { 540266072Sdes /* 541266072Sdes * Drop unencrypted frames. 542266072Sdes */ 543266072Sdes vap->iv_stats.is_rx_unencrypted++; 544266072Sdes IEEE80211_NODE_STAT(ni, rx_unencrypted); 545266072Sdes goto out; 546266072Sdes } 547266072Sdes } 548266072Sdes /* XXX require HT? */ 549266072Sdes if (qos & IEEE80211_QOS_AMSDU) { 550266072Sdes m = ieee80211_decap_amsdu(ni, m); 551266072Sdes if (m == NULL) 552266072Sdes return IEEE80211_FC0_TYPE_DATA; 553266072Sdes } else if ((ni->ni_ath_flags & IEEE80211_NODE_FF) && 554266072Sdes#define FF_LLC_SIZE (sizeof(struct ether_header) + sizeof(struct llc)) 555266072Sdes m->m_pkthdr.len >= 3*FF_LLC_SIZE) { 556266072Sdes struct llc *llc; 557266072Sdes 558266072Sdes /* 559266072Sdes * Check for fast-frame tunnel encapsulation. 560266072Sdes */ 561266072Sdes if (m->m_len < FF_LLC_SIZE && 562266072Sdes (m = m_pullup(m, FF_LLC_SIZE)) == NULL) { 563266072Sdes IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, 564266072Sdes ni->ni_macaddr, "fast-frame", 565266072Sdes "%s", "m_pullup(llc) failed"); 566266072Sdes vap->iv_stats.is_rx_tooshort++; 567266072Sdes return IEEE80211_FC0_TYPE_DATA; 568266072Sdes } 569266072Sdes llc = (struct llc *)(mtod(m, uint8_t *) + 570266072Sdes sizeof(struct ether_header)); 571266072Sdes if (llc->llc_snap.ether_type == htons(ATH_FF_ETH_TYPE)) { 572266072Sdes m_adj(m, FF_LLC_SIZE); 573266072Sdes m = ieee80211_decap_fastframe(ni, m); 574266072Sdes if (m == NULL) 575266072Sdes return IEEE80211_FC0_TYPE_DATA; 576266072Sdes } 577266072Sdes } 578266072Sdes#undef FF_LLC_SIZE 579266072Sdes if (dir == IEEE80211_FC1_DIR_DSTODS && ni->ni_wdsvap != NULL) 580266072Sdes ieee80211_deliver_data(ni->ni_wdsvap, ni, m); 581266072Sdes else 582266072Sdes ieee80211_deliver_data(vap, ni, m); 583266072Sdes return IEEE80211_FC0_TYPE_DATA; 584266072Sdes 585266072Sdes case IEEE80211_FC0_TYPE_MGT: 586266072Sdes vap->iv_stats.is_rx_mgmt++; 587266072Sdes IEEE80211_NODE_STAT(ni, rx_mgmt); 588266072Sdes if (dir != IEEE80211_FC1_DIR_NODS) { 589266072Sdes IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, 590266072Sdes wh, "data", "incorrect dir 0x%x", dir); 591266072Sdes vap->iv_stats.is_rx_wrongdir++; 592266072Sdes goto err; 593266072Sdes } 594266072Sdes if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) { 595266072Sdes IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY, 596266072Sdes ni->ni_macaddr, "mgt", "too short: len %u", 597266072Sdes m->m_pkthdr.len); 598266072Sdes vap->iv_stats.is_rx_tooshort++; 599266072Sdes goto out; 600266072Sdes } 601266072Sdes#ifdef IEEE80211_DEBUG 602266072Sdes if ((ieee80211_msg_debug(vap) && doprint(vap, subtype)) || 603266072Sdes ieee80211_msg_dumppkts(vap)) { 604266072Sdes if_printf(ifp, "received %s from %s rssi %d\n", 605266072Sdes ieee80211_mgt_subtype_name[subtype >> 606266072Sdes IEEE80211_FC0_SUBTYPE_SHIFT], 607266072Sdes ether_sprintf(wh->i_addr2), rssi); 608266072Sdes } 609266072Sdes#endif 610266072Sdes if (wh->i_fc[1] & IEEE80211_FC1_WEP) { 611266072Sdes IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, 612266072Sdes wh, NULL, "%s", "WEP set but not permitted"); 613266072Sdes vap->iv_stats.is_rx_mgtdiscard++; /* XXX */ 614266072Sdes goto out; 615266072Sdes } 616266072Sdes if (bpf_peers_present(vap->iv_rawbpf)) 617266072Sdes bpf_mtap(vap->iv_rawbpf, m); 618266072Sdes /* NB: only IBSS mode gets mgt frames */ 619266072Sdes if (vap->iv_opmode == IEEE80211_M_IBSS) 620266072Sdes vap->iv_recv_mgmt(ni, m, subtype, rssi, noise, rstamp); 621266072Sdes m_freem(m); 622266072Sdes return IEEE80211_FC0_TYPE_MGT; 623266072Sdes 624266072Sdes case IEEE80211_FC0_TYPE_CTL: 625266072Sdes vap->iv_stats.is_rx_ctl++; 626266072Sdes IEEE80211_NODE_STAT(ni, rx_ctrl); 627266072Sdes goto out; 628266072Sdes default: 629266072Sdes IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, 630266072Sdes wh, "bad", "frame type 0x%x", type); 631266072Sdes /* should not come here */ 632266072Sdes break; 633266072Sdes } 634266072Sdeserr: 635266072Sdes ifp->if_ierrors++; 636266072Sdesout: 637266072Sdes if (m != NULL) { 638266072Sdes if (bpf_peers_present(vap->iv_rawbpf) && need_tap) 639266072Sdes bpf_mtap(vap->iv_rawbpf, m); 640266072Sdes m_freem(m); 641266072Sdes } 642266072Sdes return type; 643266072Sdes#undef SEQ_LEQ 644266072Sdes} 645266072Sdes 646266072Sdesstatic int 647266072Sdesis11bclient(const uint8_t *rates, const uint8_t *xrates) 648266072Sdes{ 649266072Sdes static const uint32_t brates = (1<<2*1)|(1<<2*2)|(1<<11)|(1<<2*11); 650266072Sdes int i; 651266072Sdes 652266072Sdes /* NB: the 11b clients we care about will not have xrates */ 653266072Sdes if (xrates != NULL || rates == NULL) 654266072Sdes return 0; 655266072Sdes for (i = 0; i < rates[1]; i++) { 656266072Sdes int r = rates[2+i] & IEEE80211_RATE_VAL; 657266072Sdes if (r > 2*11 || ((1<<r) & brates) == 0) 658266072Sdes return 0; 659266072Sdes } 660266072Sdes return 1; 661266072Sdes} 662266072Sdes 663266072Sdesstatic void 664266072Sdesadhoc_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, 665266072Sdes int subtype, int rssi, int noise, uint32_t rstamp) 666266072Sdes{ 667266072Sdes struct ieee80211vap *vap = ni->ni_vap; 668266072Sdes struct ieee80211com *ic = ni->ni_ic; 669266072Sdes struct ieee80211_frame *wh; 670266072Sdes uint8_t *frm, *efrm, *sfrm; 671266072Sdes uint8_t *ssid, *rates, *xrates; 672266072Sdes 673266072Sdes wh = mtod(m0, struct ieee80211_frame *); 674266072Sdes frm = (uint8_t *)&wh[1]; 675266072Sdes efrm = mtod(m0, uint8_t *) + m0->m_len; 676266072Sdes switch (subtype) { 677266072Sdes case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 678266072Sdes case IEEE80211_FC0_SUBTYPE_BEACON: { 679266072Sdes struct ieee80211_scanparams scan; 680266072Sdes /* 681266072Sdes * We process beacon/probe response 682266072Sdes * frames to discover neighbors. 683266072Sdes */ 684266072Sdes if (ieee80211_parse_beacon(ni, m0, &scan) != 0) 685266072Sdes return; 686266072Sdes /* 687266072Sdes * Count frame now that we know it's to be processed. 688266072Sdes */ 689266072Sdes if (subtype == IEEE80211_FC0_SUBTYPE_BEACON) { 690266072Sdes vap->iv_stats.is_rx_beacon++; /* XXX remove */ 691266072Sdes IEEE80211_NODE_STAT(ni, rx_beacons); 692266072Sdes } else 693266072Sdes IEEE80211_NODE_STAT(ni, rx_proberesp); 694266072Sdes /* 695266072Sdes * If scanning, just pass information to the scan module. 696266072Sdes */ 697266072Sdes if (ic->ic_flags & IEEE80211_F_SCAN) { 698266072Sdes if (ic->ic_flags_ext & IEEE80211_FEXT_PROBECHAN) { 699266072Sdes /* 700266072Sdes * Actively scanning a channel marked passive; 701266072Sdes * send a probe request now that we know there 702266072Sdes * is 802.11 traffic present. 703266072Sdes * 704266072Sdes * XXX check if the beacon we recv'd gives 705266072Sdes * us what we need and suppress the probe req 706266072Sdes */ 707266072Sdes ieee80211_probe_curchan(vap, 1); 708266072Sdes ic->ic_flags_ext &= ~IEEE80211_FEXT_PROBECHAN; 709266072Sdes } 710266072Sdes ieee80211_add_scan(vap, &scan, wh, 711266072Sdes subtype, rssi, noise, rstamp); 712266072Sdes return; 713266072Sdes } 714266072Sdes if (scan.capinfo & IEEE80211_CAPINFO_IBSS) { 715266072Sdes if (!IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_macaddr)) { 716266072Sdes /* 717266072Sdes * Create a new entry in the neighbor table. 718266072Sdes */ 719266072Sdes ni = ieee80211_add_neighbor(vap, wh, &scan); 720266072Sdes } else if (ni->ni_capinfo == 0) { 721266072Sdes /* 722266072Sdes * Update faked node created on transmit. 723266072Sdes * Note this also updates the tsf. 724266072Sdes */ 725266072Sdes ieee80211_init_neighbor(ni, wh, &scan); 726266072Sdes } else { 727266072Sdes /* 728266072Sdes * Record tsf for potential resync. 729266072Sdes */ 730266072Sdes memcpy(ni->ni_tstamp.data, scan.tstamp, 731266072Sdes sizeof(ni->ni_tstamp)); 732266072Sdes } 733266072Sdes if (ni != NULL) { 734266072Sdes IEEE80211_RSSI_LPF(ni->ni_avgrssi, rssi); 735266072Sdes ni->ni_noise = noise; 736266072Sdes ni->ni_rstamp = rstamp; 737266072Sdes } 738266072Sdes } 739266072Sdes break; 740266072Sdes } 741266072Sdes 742266072Sdes case IEEE80211_FC0_SUBTYPE_PROBE_REQ: 743266072Sdes if (vap->iv_state != IEEE80211_S_RUN) { 744266072Sdes vap->iv_stats.is_rx_mgtdiscard++; 745266072Sdes return; 746266072Sdes } 747266072Sdes if (IEEE80211_IS_MULTICAST(wh->i_addr2)) { 748266072Sdes /* frame must be directed */ 749266072Sdes vap->iv_stats.is_rx_mgtdiscard++; /* XXX stat */ 750266072Sdes return; 751266072Sdes } 752266072Sdes 753266072Sdes /* 754266072Sdes * prreq frame format 755266072Sdes * [tlv] ssid 756266072Sdes * [tlv] supported rates 757266072Sdes * [tlv] extended supported rates 758266072Sdes */ 759266072Sdes ssid = rates = xrates = NULL; 760266072Sdes sfrm = frm; 761266072Sdes while (efrm - frm > 1) { 762266072Sdes IEEE80211_VERIFY_LENGTH(efrm - frm, frm[1] + 2, return); 763266072Sdes switch (*frm) { 764266072Sdes case IEEE80211_ELEMID_SSID: 765266072Sdes ssid = frm; 766266072Sdes break; 767266072Sdes case IEEE80211_ELEMID_RATES: 768266072Sdes rates = frm; 769266072Sdes break; 770266072Sdes case IEEE80211_ELEMID_XRATES: 771266072Sdes xrates = frm; 772266072Sdes break; 773266072Sdes } 774266072Sdes frm += frm[1] + 2; 775266072Sdes } 776266072Sdes IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE, return); 777266072Sdes if (xrates != NULL) 778266072Sdes IEEE80211_VERIFY_ELEMENT(xrates, 779266072Sdes IEEE80211_RATE_MAXSIZE - rates[1], return); 780266072Sdes IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN, return); 781266072Sdes IEEE80211_VERIFY_SSID(vap->iv_bss, ssid, return); 782266072Sdes if ((vap->iv_flags & IEEE80211_F_HIDESSID) && ssid[1] == 0) { 783266072Sdes IEEE80211_DISCARD(vap, IEEE80211_MSG_INPUT, 784266072Sdes wh, NULL, 785266072Sdes "%s", "no ssid with ssid suppression enabled"); 786266072Sdes vap->iv_stats.is_rx_ssidmismatch++; /*XXX*/ 787266072Sdes return; 788266072Sdes } 789266072Sdes 790266072Sdes /* XXX find a better class or define it's own */ 791266072Sdes IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_INPUT, wh->i_addr2, 792266072Sdes "%s", "recv probe req"); 793266072Sdes /* 794266072Sdes * Some legacy 11b clients cannot hack a complete 795266072Sdes * probe response frame. When the request includes 796266072Sdes * only a bare-bones rate set, communicate this to 797266072Sdes * the transmit side. 798266072Sdes */ 799266072Sdes ieee80211_send_proberesp(vap, wh->i_addr2, 800266072Sdes is11bclient(rates, xrates) ? IEEE80211_SEND_LEGACY_11B : 0); 801266072Sdes break; 802266072Sdes 803266072Sdes case IEEE80211_FC0_SUBTYPE_ACTION: { 804266072Sdes const struct ieee80211_action *ia; 805266072Sdes 806266072Sdes if (vap->iv_state != IEEE80211_S_RUN) { 807266072Sdes vap->iv_stats.is_rx_mgtdiscard++; 808266072Sdes return; 809266072Sdes } 810266072Sdes /* 811266072Sdes * action frame format: 812266072Sdes * [1] category 813266072Sdes * [1] action 814266072Sdes * [tlv] parameters 815266072Sdes */ 816266072Sdes IEEE80211_VERIFY_LENGTH(efrm - frm, 817266072Sdes sizeof(struct ieee80211_action), return); 818266072Sdes ia = (const struct ieee80211_action *) frm; 819266072Sdes 820266072Sdes vap->iv_stats.is_rx_action++; 821266072Sdes IEEE80211_NODE_STAT(ni, rx_action); 822266072Sdes 823266072Sdes /* verify frame payloads but defer processing */ 824266072Sdes /* XXX maybe push this to method */ 825266072Sdes switch (ia->ia_category) { 826266072Sdes case IEEE80211_ACTION_CAT_BA: 827266072Sdes switch (ia->ia_action) { 828266072Sdes case IEEE80211_ACTION_BA_ADDBA_REQUEST: 829266072Sdes IEEE80211_VERIFY_LENGTH(efrm - frm, 830266072Sdes sizeof(struct ieee80211_action_ba_addbarequest), 831266072Sdes return); 832266072Sdes break; 833266072Sdes case IEEE80211_ACTION_BA_ADDBA_RESPONSE: 834266072Sdes IEEE80211_VERIFY_LENGTH(efrm - frm, 835266072Sdes sizeof(struct ieee80211_action_ba_addbaresponse), 836266072Sdes return); 837266072Sdes break; 838266072Sdes case IEEE80211_ACTION_BA_DELBA: 839266072Sdes IEEE80211_VERIFY_LENGTH(efrm - frm, 840266072Sdes sizeof(struct ieee80211_action_ba_delba), 841266072Sdes return); 842266072Sdes break; 843266072Sdes } 844266072Sdes break; 845266072Sdes case IEEE80211_ACTION_CAT_HT: 846266072Sdes switch (ia->ia_action) { 847266072Sdes case IEEE80211_ACTION_HT_TXCHWIDTH: 848266072Sdes IEEE80211_VERIFY_LENGTH(efrm - frm, 849266072Sdes sizeof(struct ieee80211_action_ht_txchwidth), 850266072Sdes return); 851266072Sdes break; 852266072Sdes } 853266072Sdes break; 854266072Sdes } 855266072Sdes ic->ic_recv_action(ni, frm, efrm); 856266072Sdes break; 857266072Sdes } 858266072Sdes 859266072Sdes case IEEE80211_FC0_SUBTYPE_AUTH: 860266072Sdes case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: 861266072Sdes case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: 862266072Sdes case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: 863266072Sdes case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: 864266072Sdes case IEEE80211_FC0_SUBTYPE_DEAUTH: 865266072Sdes case IEEE80211_FC0_SUBTYPE_DISASSOC: 866266072Sdes vap->iv_stats.is_rx_mgtdiscard++; 867266072Sdes return; 868266072Sdes 869266072Sdes default: 870266072Sdes IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, 871266072Sdes wh, "mgt", "subtype 0x%x not handled", subtype); 872266072Sdes vap->iv_stats.is_rx_badsubtype++; 873266072Sdes break; 874266072Sdes } 875266072Sdes} 876266072Sdes#undef IEEE80211_VERIFY_LENGTH 877266072Sdes#undef IEEE80211_VERIFY_ELEMENT 878266072Sdes