| 1 | /*- |
| 2 | * SPDX-License-Identifier: BSD-2-Clause |
| 3 | * |
| 4 | * Copyright (c) 2005-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 | #ifndef _NET80211_IEEE80211_SCAN_H_ |
| 28 | #define _NET80211_IEEE80211_SCAN_H_ |
| 29 | |
| 30 | /* |
| 31 | * 802.11 scanning support. |
| 32 | * |
| 33 | * Scanning is the procedure by which a station locates a bss to join |
| 34 | * (infrastructure/ibss mode), or a channel to use (when operating as |
| 35 | * an ap or ibss master). Scans are either "active" or "passive". An |
| 36 | * active scan causes one or more probe request frames to be sent on |
| 37 | * visiting each channel. A passive request causes each channel in the |
| 38 | * scan set to be visited but no frames to be transmitted; the station |
| 39 | * only listens for traffic. Note that active scanning may still need |
| 40 | * to listen for traffic before sending probe request frames depending |
| 41 | * on regulatory constraints; the 802.11 layer handles this by generating |
| 42 | * a callback when scanning on a ``passive channel'' when the |
| 43 | * IEEE80211_FEXT_PROBECHAN flag is set. |
| 44 | * |
| 45 | * A scan operation involves constructing a set of channels to inspect |
| 46 | * (the scan set), visiting each channel and collecting information |
| 47 | * (e.g. what bss are present), and then analyzing the results to make |
| 48 | * decisions like which bss to join. This process needs to be as fast |
| 49 | * as possible so we do things like intelligently construct scan sets |
| 50 | * and dwell on a channel only as long as necessary. The scan code also |
| 51 | * maintains a cache of recent scan results and uses it to bypass scanning |
| 52 | * whenever possible. The scan cache is also used to enable roaming |
| 53 | * between access points when operating in infrastructure mode. |
| 54 | * |
| 55 | * Scanning is handled with pluggable modules that implement "policy" |
| 56 | * per-operating mode. The core scanning support provides an |
| 57 | * instrastructure to support these modules and exports a common api |
| 58 | * to the rest of the 802.11 layer. Policy modules decide what |
| 59 | * channels to visit, what state to record to make decisions (e.g. ap |
| 60 | * mode scanning for auto channel selection keeps significantly less |
| 61 | * state than sta mode scanning for an ap to associate to), and selects |
| 62 | * the final station/channel to return as the result of a scan. |
| 63 | * |
| 64 | * Scanning is done synchronously when initially bringing a vap to an |
| 65 | * operational state and optionally in the background to maintain the |
| 66 | * scan cache for doing roaming and rogue ap monitoring. Scanning is |
| 67 | * not tied to the 802.11 state machine that governs vaps though there |
| 68 | * is linkage to the IEEE80211_SCAN state. Only one vap at a time may |
| 69 | * be scanning; this scheduling policy is handled in ieee80211_new_state |
| 70 | * and is invisible to the scanning code. |
| 71 | */ |
| 72 | #define	IEEE80211_SCAN_MAX	IEEE80211_CHAN_MAX |
| 73 | |
| 74 | struct ieee80211_scanner;			/* scan policy state */ |
| 75 | |
| 76 | struct ieee80211_scan_ssid { |
| 77 | 	int	 len;				/* length in bytes */ |
| 78 | 	uint8_t ssid[IEEE80211_NWID_LEN];	/* ssid contents */ |
| 79 | }; |
| 80 | #define	IEEE80211_SCAN_MAX_SSID	1		/* max # ssid's to probe */ |
| 81 | |
| 82 | /* |
| 83 | * High-level implementation visible to ieee80211_scan.[ch]. |
| 84 | * |
| 85 | * The default scanner (ieee80211_scan_sw.[ch]) implements a software |
| 86 | * driven scanner. Firmware driven scanning needs a different set of |
| 87 | * behaviours. |
| 88 | */ |
| 89 | struct ieee80211_scan_methods { |
| 90 | 	void (*sc_attach)(struct ieee80211com *); |
| 91 | 	void (*sc_detach)(struct ieee80211com *); |
| 92 | 	void (*sc_vattach)(struct ieee80211vap *); |
| 93 | 	void (*sc_vdetach)(struct ieee80211vap *); |
| 94 | 	void (*sc_set_scan_duration)(struct ieee80211vap *, u_int); |
| 95 | 	int (*sc_start_scan)(const struct ieee80211_scanner *, |
| 96 | 	 struct ieee80211vap *, int, u_int, u_int, u_int, u_int, |
| 97 | 	 const struct ieee80211_scan_ssid ssids[]); |
| 98 | 	int (*sc_check_scan)(const struct ieee80211_scanner *, |
| 99 | 	 struct ieee80211vap *, int, u_int, u_int, u_int, u_int, |
| 100 | 	 const struct ieee80211_scan_ssid ssids[]); |
| 101 | 	int (*sc_bg_scan)(const struct ieee80211_scanner *, |
| 102 | 	 struct ieee80211vap *, int); |
| 103 | 	void (*sc_cancel_scan)(struct ieee80211vap *); |
| 104 | 	void (*sc_cancel_anyscan)(struct ieee80211vap *); |
| 105 | 	void (*sc_scan_next)(struct ieee80211vap *); |
| 106 | 	void (*sc_scan_done)(struct ieee80211vap *); |
| 107 | 	void (*sc_scan_probe_curchan)(struct ieee80211vap *, bool); |
| 108 | 	void (*sc_add_scan)(struct ieee80211vap *, |
| 109 | 	 struct ieee80211_channel *, |
| 110 | 	 const struct ieee80211_scanparams *, |
| 111 | 	 const struct ieee80211_frame *, |
| 112 | 	 int, int, int); |
| 113 | }; |
| 114 | |
| 115 | /* |
| 116 | * Scan state visible to the 802.11 layer. Scan parameters and |
| 117 | * results are stored in this data structure. The ieee80211_scan_state |
| 118 | * structure is extended with space that is maintained private to |
| 119 | * the core scanning support. We allocate one instance and link it |
| 120 | * to the ieee80211com structure; then share it between all associated |
| 121 | * vaps. We could allocate multiple of these, e.g. to hold multiple |
| 122 | * scan results, but this is sufficient for current needs. |
| 123 | */ |
| 124 | struct ieee80211_scan_state { |
| 125 | 	struct ieee80211vap *ss_vap; |
| 126 | 	struct ieee80211com *ss_ic; |
| 127 | 	const struct ieee80211_scanner *ss_ops;	/* policy hookup, see below */ |
| 128 | 	void		*ss_priv;		/* scanner private state */ |
| 129 | 	uint16_t	ss_flags; |
| 130 | #define	IEEE80211_SCAN_NOPICK	0x0001		/* scan only, no selection */ |
| 131 | #define	IEEE80211_SCAN_ACTIVE	0x0002		/* active scan (probe req) */ |
| 132 | #define	IEEE80211_SCAN_PICK1ST	0x0004		/* ``hey sailor'' mode */ |
| 133 | #define	IEEE80211_SCAN_BGSCAN	0x0008		/* bg scan, exit ps at end */ |
| 134 | #define	IEEE80211_SCAN_ONCE	0x0010		/* do one complete pass */ |
| 135 | #define	IEEE80211_SCAN_NOBCAST	0x0020		/* no broadcast probe req */ |
| 136 | #define	IEEE80211_SCAN_NOJOIN	0x0040		/* no auto-sequencing */ |
| 137 | #define	IEEE80211_SCAN_PUBLIC_MASK	0x0fff	/* top 4 bits for internal use */ |
| 138 | #define	IEEE80211_SCAN_GOTPICK	0x1000		/* got candidate, can stop */ |
| 139 | 	uint8_t		ss_nssid;		/* # ssid's to probe/match */ |
| 140 | 	struct ieee80211_scan_ssid ss_ssid[IEEE80211_SCAN_MAX_SSID]; |
| 141 | 						/* ssid's to probe/match */ |
| 142 | 						/* ordered channel set */ |
| 143 | 	struct ieee80211_channel *ss_chans[IEEE80211_SCAN_MAX]; |
| 144 | 	uint16_t	ss_next;		/* ix of next chan to scan */ |
| 145 | 	uint16_t	ss_last;		/* ix+1 of last chan to scan */ |
| 146 | 	unsigned long	ss_mindwell;		/* min dwell on channel */ |
| 147 | 	unsigned long	ss_maxdwell;		/* max dwell on channel */ |
| 148 | }; |
| 149 | |
| 150 | #define	IEEE80211_SS_FLAGS_BITS \ |
| 151 | 	"\20\1NOPICK\2ACTIVE\3PICK1ST\4BGSCAN\5ONCE\6NOBCAST\7NOJOIN" \ |
| 152 | 	"\15GOTPICK" |
| 153 | |
| 154 | /* |
| 155 | * The upper 16 bits of the flags word is used to communicate |
| 156 | * information to the scanning code that is NOT recorded in |
| 157 | * ss_flags. It might be better to split this stuff out into |
| 158 | * a separate variable to avoid confusion. |
| 159 | */ |
| 160 | #define	IEEE80211_SCAN_FLUSH	0x00010000	/* flush candidate table */ |
| 161 | #define	IEEE80211_SCAN_NOSSID	0x80000000	/* don't update ssid list */ |
| 162 | |
| 163 | struct ieee80211com; |
| 164 | void	ieee80211_scan_attach(struct ieee80211com *); |
| 165 | void	ieee80211_scan_detach(struct ieee80211com *); |
| 166 | void	ieee80211_scan_vattach(struct ieee80211vap *); |
| 167 | void	ieee80211_scan_vdetach(struct ieee80211vap *); |
| 168 | |
| 169 | #define	IEEE80211_SCAN_FOREVER	0x7fffffff |
| 170 | int	ieee80211_start_scan(struct ieee80211vap *, int flags, |
| 171 | 		u_int duration, u_int mindwell, u_int maxdwell, |
| 172 | 		u_int nssid, const struct ieee80211_scan_ssid ssids[]); |
| 173 | int	ieee80211_check_scan(struct ieee80211vap *, int flags, |
| 174 | 		u_int duration, u_int mindwell, u_int maxdwell, |
| 175 | 		u_int nssid, const struct ieee80211_scan_ssid ssids[]); |
| 176 | int	ieee80211_check_scan_current(struct ieee80211vap *); |
| 177 | int	ieee80211_bg_scan(struct ieee80211vap *, int); |
| 178 | void	ieee80211_cancel_scan(struct ieee80211vap *); |
| 179 | void	ieee80211_cancel_anyscan(struct ieee80211vap *); |
| 180 | void	ieee80211_scan_next(struct ieee80211vap *); |
| 181 | void	ieee80211_scan_done(struct ieee80211vap *); |
| 182 | void	ieee80211_probe_curchan(struct ieee80211vap *, bool); |
| 183 | struct ieee80211_channel *ieee80211_scan_pickchannel(struct ieee80211com *, int); |
| 184 | |
| 185 | struct ieee80211_scanparams; |
| 186 | void	ieee80211_add_scan(struct ieee80211vap *, |
| 187 | 		struct ieee80211_channel *, |
| 188 | 		const struct ieee80211_scanparams *, |
| 189 | 		const struct ieee80211_frame *, |
| 190 | 		int subtype, int rssi, int noise); |
| 191 | void	ieee80211_scan_timeout(struct ieee80211com *); |
| 192 | |
| 193 | void	ieee80211_scan_assoc_success(struct ieee80211vap *, |
| 194 | 		const uint8_t mac[IEEE80211_ADDR_LEN]); |
| 195 | enum { |
| 196 | 	IEEE80211_SCAN_FAIL_TIMEOUT	= 1,	/* no response to mgmt frame */ |
| 197 | 	IEEE80211_SCAN_FAIL_STATUS	= 2	/* negative response to " " */ |
| 198 | }; |
| 199 | void	ieee80211_scan_assoc_fail(struct ieee80211vap *, |
| 200 | 		const uint8_t mac[IEEE80211_ADDR_LEN], int reason); |
| 201 | void	ieee80211_scan_flush(struct ieee80211vap *); |
| 202 | |
| 203 | struct ieee80211_scan_entry; |
| 204 | typedef void ieee80211_scan_iter_func(void *, |
| 205 | 		const struct ieee80211_scan_entry *); |
| 206 | void	ieee80211_scan_iterate(struct ieee80211vap *, |
| 207 | 		ieee80211_scan_iter_func, void *); |
| 208 | enum { |
| 209 | 	IEEE80211_BPARSE_BADIELEN	= 0x01,	/* ie len past end of frame */ |
| 210 | 	IEEE80211_BPARSE_RATES_INVALID	= 0x02,	/* invalid RATES ie */ |
| 211 | 	IEEE80211_BPARSE_XRATES_INVALID	= 0x04,	/* invalid XRATES ie */ |
| 212 | 	IEEE80211_BPARSE_SSID_INVALID	= 0x08,	/* invalid SSID ie */ |
| 213 | 	IEEE80211_BPARSE_CHAN_INVALID	= 0x10,	/* invalid FH/DSPARMS chan */ |
| 214 | 	IEEE80211_BPARSE_OFFCHAN	= 0x20,	/* DSPARMS chan != curchan */ |
| 215 | 	IEEE80211_BPARSE_BINTVAL_INVALID= 0x40,	/* invalid beacon interval */ |
| 216 | 	IEEE80211_BPARSE_CSA_INVALID	= 0x80,	/* invalid CSA ie */ |
| 217 | 	IEEE80211_BPARSE_MESHID_INVALID = 0x100, /* invalid Mesh ID ie */ |
| 218 | }; |
| 219 | |
| 220 | /* |
| 221 | * Parameters supplied when adding/updating an entry in a |
| 222 | * scan cache. Pointer variables should be set to NULL |
| 223 | * if no data is available. Pointer references can be to |
| 224 | * local data; any information that is saved will be copied. |
| 225 | * All multi-byte values must be in host byte order. |
| 226 | */ |
| 227 | struct ieee80211_scanparams { |
| 228 | 	uint32_t	status;		/* bitmask of IEEE80211_BPARSE_* */ |
| 229 | 	uint8_t		chan;		/* channel # from FH/DSPARMS */ |
| 230 | 	uint8_t		bchan;		/* curchan's channel # */ |
| 231 | 	uint8_t		fhindex; |
| 232 | 	uint16_t	fhdwell;	/* FHSS dwell interval */ |
| 233 | 	uint16_t	capinfo;	/* 802.11 capabilities */ |
| 234 | 	uint16_t	erp;		/* NB: 0x100 indicates ie present */ |
| 235 | 	uint16_t	bintval; |
| 236 | 	uint8_t		timoff; |
| 237 | 	uint8_t		*ies;		/* all captured ies */ |
| 238 | 	size_t		ies_len;	/* length of all captured ies */ |
| 239 | 	uint8_t		*tim; |
| 240 | 	uint8_t		*tstamp; |
| 241 | 	uint8_t		*country; |
| 242 | 	uint8_t		*ssid; |
| 243 | 	uint8_t		*rates; |
| 244 | 	uint8_t		*xrates; |
| 245 | 	uint8_t		*doth; |
| 246 | 	uint8_t		*wpa; |
| 247 | 	uint8_t		*rsn; |
| 248 | 	uint8_t		*wme; |
| 249 | 	uint8_t		*htcap; |
| 250 | 	uint8_t		*htinfo; |
| 251 | 	uint8_t		*ath; |
| 252 | 	uint8_t		*tdma; |
| 253 | 	uint8_t		*csa; |
| 254 | 	uint8_t		*quiet; |
| 255 | 	uint8_t		*meshid; |
| 256 | 	uint8_t		*meshconf; |
| 257 | 	uint8_t		*vhtcap; |
| 258 | 	uint8_t		*vhtopmode; |
| 259 | 	uint8_t		*spare[1]; |
| 260 | }; |
| 261 | |
| 262 | /* |
| 263 | * Scan cache entry format used when exporting data from a policy |
| 264 | * module; this data may be represented some other way internally. |
| 265 | */ |
| 266 | struct ieee80211_scan_entry { |
| 267 | 	uint8_t		se_macaddr[IEEE80211_ADDR_LEN]; |
| 268 | 	uint8_t		se_bssid[IEEE80211_ADDR_LEN]; |
| 269 | 	/* XXX can point inside se_ies */ |
| 270 | 	uint8_t		se_ssid[2+IEEE80211_NWID_LEN]; |
| 271 | 	uint8_t		se_rates[2+IEEE80211_RATE_MAXSIZE]; |
| 272 | 	uint8_t		se_xrates[2+IEEE80211_RATE_MAXSIZE]; |
| 273 | 	union { |
| 274 | 		uint8_t		data[8]; |
| 275 | 		u_int64_t	tsf; |
| 276 | 	} se_tstamp;			/* from last rcv'd beacon */ |
| 277 | 	uint16_t	se_intval;	/* beacon interval (host byte order) */ |
| 278 | 	uint16_t	se_capinfo;	/* capabilities (host byte order) */ |
| 279 | 	struct ieee80211_channel *se_chan;/* channel where sta found */ |
| 280 | 	uint16_t	se_timoff;	/* byte offset to TIM ie */ |
| 281 | 	uint16_t	se_fhdwell;	/* FH only (host byte order) */ |
| 282 | 	uint8_t		se_fhindex;	/* FH only */ |
| 283 | 	uint8_t		se_dtimperiod;	/* DTIM period */ |
| 284 | 	uint16_t	se_erp;		/* ERP from beacon/probe resp */ |
| 285 | 	int8_t		se_rssi;	/* avg'd recv ssi */ |
| 286 | 	int8_t		se_noise;	/* noise floor */ |
| 287 | 	uint8_t		se_cc[2];	/* captured country code */ |
| 288 | 	uint8_t		se_meshid[2+IEEE80211_MESHID_LEN]; |
| 289 | 	struct ieee80211_ies se_ies;	/* captured ie's */ |
| 290 | 	u_int		se_age;		/* age of entry (0 on create) */ |
| 291 | }; |
| 292 | MALLOC_DECLARE(M_80211_SCAN); |
| 293 | |
| 294 | /* |
| 295 | * Template for an in-kernel scan policy module. |
| 296 | * Modules register with the scanning code and are |
| 297 | * typically loaded as needed. |
| 298 | */ |
| 299 | struct ieee80211_scanner { |
| 300 | 	const char *scan_name;		/* printable name */ |
| 301 | 	int	(*scan_attach)(struct ieee80211_scan_state *); |
| 302 | 	int	(*scan_detach)(struct ieee80211_scan_state *); |
| 303 | 	int	(*scan_start)(struct ieee80211_scan_state *, |
| 304 | 			struct ieee80211vap *); |
| 305 | 	int	(*scan_restart)(struct ieee80211_scan_state *, |
| 306 | 			struct ieee80211vap *); |
| 307 | 	int	(*scan_cancel)(struct ieee80211_scan_state *, |
| 308 | 			struct ieee80211vap *); |
| 309 | 	int	(*scan_end)(struct ieee80211_scan_state *, |
| 310 | 			struct ieee80211vap *); |
| 311 | 	int	(*scan_flush)(struct ieee80211_scan_state *); |
| 312 | 	struct ieee80211_channel *(*scan_pickchan)( |
| 313 | 			struct ieee80211_scan_state *, int); |
| 314 | 	/* add an entry to the cache */ |
| 315 | 	int	(*scan_add)(struct ieee80211_scan_state *, |
| 316 | 			struct ieee80211_channel *, |
| 317 | 			const struct ieee80211_scanparams *, |
| 318 | 			const struct ieee80211_frame *, |
| 319 | 			int subtype, int rssi, int noise); |
| 320 | 	/* age and/or purge entries in the cache */ |
| 321 | 	void	(*scan_age)(struct ieee80211_scan_state *); |
| 322 | 	/* note that association failed for an entry */ |
| 323 | 	void	(*scan_assoc_fail)(struct ieee80211_scan_state *, |
| 324 | 			const uint8_t macaddr[IEEE80211_ADDR_LEN], |
| 325 | 			int reason); |
| 326 | 	/* note that association succeed for an entry */ |
| 327 | 	void	(*scan_assoc_success)(struct ieee80211_scan_state *, |
| 328 | 			const uint8_t macaddr[IEEE80211_ADDR_LEN]); |
| 329 | 	/* iterate over entries in the scan cache */ |
| 330 | 	void	(*scan_iterate)(struct ieee80211_scan_state *, |
| 331 | 			ieee80211_scan_iter_func *, void *); |
| 332 | 	void	(*scan_spare0)(void); |
| 333 | 	void	(*scan_spare1)(void); |
| 334 | 	void	(*scan_spare2)(void); |
| 335 | 	void	(*scan_spare3)(void); |
| 336 | }; |
| 337 | void	ieee80211_scanner_register(enum ieee80211_opmode, |
| 338 | 		const struct ieee80211_scanner *); |
| 339 | void	ieee80211_scanner_unregister(enum ieee80211_opmode, |
| 340 | 		const struct ieee80211_scanner *); |
| 341 | void	ieee80211_scanner_unregister_all(const struct ieee80211_scanner *); |
| 342 | const struct ieee80211_scanner *ieee80211_scanner_get(enum ieee80211_opmode); |
| 343 | void	ieee80211_scan_update_locked(struct ieee80211vap *vap, |
| 344 | 		const struct ieee80211_scanner *scan); |
| 345 | void	ieee80211_scan_copy_ssid(struct ieee80211vap *vap, |
| 346 | 		struct ieee80211_scan_state *ss, |
| 347 | 		int nssid, const struct ieee80211_scan_ssid ssids[]); |
| 348 | void	ieee80211_scan_dump_probe_beacon(uint8_t subtype, int isnew, |
| 349 | 		const uint8_t mac[IEEE80211_ADDR_LEN], |
| 350 | 		const struct ieee80211_scanparams *sp, int rssi); |
| 351 | void	ieee80211_scan_dump(struct ieee80211_scan_state *ss); |
| 352 | |
| 353 | #endif /* _NET80211_IEEE80211_SCAN_H_ */ |