mirror of
https://git.kernel.org/pub/scm/network/wireless/iwd.git
synced 2026-01-10 07:07:58 +01:00
Compare commits
295 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e7a8feee0 | ||
|
|
3760a49650 | ||
|
|
c4d114d804 | ||
|
|
ffe79bfada | ||
|
|
c0efaf21ad | ||
|
|
cee079da5b | ||
|
|
df30309aac | ||
|
|
2fe8c13016 | ||
|
|
84666b9703 | ||
|
|
54c0dbb3c8 | ||
|
|
6e9e0928b0 | ||
|
|
a1247fe46e | ||
|
|
088bb2e308 | ||
|
|
57dc5d843c | ||
|
|
8cb134f935 | ||
|
|
46037c428c | ||
|
|
161de4a3ad | ||
|
|
77ee863f04 | ||
|
|
405d1ab77c | ||
|
|
dc1589f3fe | ||
|
|
755280a4cc | ||
|
|
df2c5cf7fa | ||
|
|
fee0e5de33 | ||
|
|
601d9b0e02 | ||
|
|
f209e00dde | ||
|
|
86523b0597 | ||
|
|
85a2637fc5 | ||
|
|
2f991918b1 | ||
|
|
5b5a9b60fb | ||
|
|
5287809043 | ||
|
|
ea9ff2dcaf | ||
|
|
9dce36fe3d | ||
|
|
c4718a5355 | ||
|
|
c9c8790ff2 | ||
|
|
d135bfc4b8 | ||
|
|
e269beadba | ||
|
|
3e55fc855a | ||
|
|
c8d9936f9d | ||
|
|
79940956ef | ||
|
|
9f98c6c3c8 | ||
|
|
93eef7b02d | ||
|
|
26ed1f8b9f | ||
|
|
243db1d256 | ||
|
|
5224b0b0e7 | ||
|
|
3267d356d2 | ||
|
|
78f4e6240e | ||
|
|
36b1086f60 | ||
|
|
266eb405f2 | ||
|
|
0a8e646231 | ||
|
|
8ebc4780ea | ||
|
|
4ded663e68 | ||
|
|
c00bc3a065 | ||
|
|
f469db8a95 | ||
|
|
c3a27354ff | ||
|
|
d927fd07c1 | ||
|
|
8dff156eb6 | ||
|
|
e5c41a8024 | ||
|
|
603d6b2881 | ||
|
|
d1aa4009bc | ||
|
|
3c5081c7a6 | ||
|
|
7d5bcd738b | ||
|
|
0a93c55552 | ||
|
|
7f9ea7640d | ||
|
|
c52d913f20 | ||
|
|
651b647570 | ||
|
|
8cf9734d2b | ||
|
|
d70fbade44 | ||
|
|
f0e515b6ff | ||
|
|
47ef40d645 | ||
|
|
9e10efbef5 | ||
|
|
224afbb9ca | ||
|
|
bf69e6210c | ||
|
|
258482d509 | ||
|
|
1caad4ca88 | ||
|
|
59464a0ca4 | ||
|
|
93b25c87d6 | ||
|
|
e971ef71d5 | ||
|
|
bff5006b38 | ||
|
|
ea571861d6 | ||
|
|
f3e4263f51 | ||
|
|
77639d2d45 | ||
|
|
1662707f22 | ||
|
|
5f4bf2a5e5 | ||
|
|
40af18f96a | ||
|
|
ab4fa30c7e | ||
|
|
43f73823ec | ||
|
|
f4439fd2b6 | ||
|
|
bf82aff039 | ||
|
|
4b535cee1f | ||
|
|
7144741537 | ||
|
|
64b872f363 | ||
|
|
83a2457550 | ||
|
|
43f895142c | ||
|
|
c352b35bf1 | ||
|
|
d4bba5c838 | ||
|
|
1dd9f94713 | ||
|
|
c458e6612d | ||
|
|
45db339dcd | ||
|
|
887d8c8fe8 | ||
|
|
c6932efa30 | ||
|
|
f3ba82b0e1 | ||
|
|
a26fcd8f2d | ||
|
|
ab49b404fd | ||
|
|
9bc71b2853 | ||
|
|
5b104967ce | ||
|
|
4680c0c13b | ||
|
|
c36358cc7c | ||
|
|
235f6e5f14 | ||
|
|
980e132f48 | ||
|
|
900aa5810e | ||
|
|
8cf83d6620 | ||
|
|
ee52bc60ff | ||
|
|
3f4a29651e | ||
|
|
f58cad8cd9 | ||
|
|
b9c3feb198 | ||
|
|
94ebc9d90b | ||
|
|
b0759ebbb2 | ||
|
|
f2ac45eb52 | ||
|
|
7c5b40ff6b | ||
|
|
7465abe5f8 | ||
|
|
a910a21beb | ||
|
|
c40e665094 | ||
|
|
bb57d61add | ||
|
|
fc2965649c | ||
|
|
fa25de4ad1 | ||
|
|
901305dcdd | ||
|
|
b4a4495537 | ||
|
|
ccd91fe556 | ||
|
|
e89e4d692c | ||
|
|
0868418ad1 | ||
|
|
d81de65533 | ||
|
|
65073ffcfa | ||
|
|
d0b9fc84b5 | ||
|
|
e0727bfeb6 | ||
|
|
8e10e00904 | ||
|
|
a2b2f66c4c | ||
|
|
ca9b7ccaf6 | ||
|
|
354bce64dd | ||
|
|
ff4edacb42 | ||
|
|
a6edf6f31e | ||
|
|
31787e3788 | ||
|
|
e98a76aefb | ||
|
|
4a04d41409 | ||
|
|
8bb22a722b | ||
|
|
c459dc75c0 | ||
|
|
1a554a300d | ||
|
|
6cc6a8a2cb | ||
|
|
b0a011d8f4 | ||
|
|
a27b7823df | ||
|
|
14b9291490 | ||
|
|
354200f9da | ||
|
|
acc5daf0e2 | ||
|
|
5c22ab6621 | ||
|
|
af99fbb6c0 | ||
|
|
4b2c6de45c | ||
|
|
30cc3ecf7b | ||
|
|
87a8884f25 | ||
|
|
4f2bf0b0a6 | ||
|
|
184c3efcb3 | ||
|
|
3f06d0128a | ||
|
|
3bc8b90c0e | ||
|
|
f6cfcb8ca2 | ||
|
|
163c2ebd37 | ||
|
|
154a29be05 | ||
|
|
23cf6107c6 | ||
|
|
c66438e34f | ||
|
|
c778ddf0c2 | ||
|
|
2ad9561069 | ||
|
|
f4ec1ee509 | ||
|
|
b98bc30c23 | ||
|
|
4c3cbdc8d3 | ||
|
|
61cba6bd28 | ||
|
|
574b0d80dc | ||
|
|
0c228f4465 | ||
|
|
1ac3915641 | ||
|
|
e9ac7ab378 | ||
|
|
7ba5b0f924 | ||
|
|
54b6330845 | ||
|
|
b5aff74e3b | ||
|
|
294426b450 | ||
|
|
4482b8dc24 | ||
|
|
bf2441e311 | ||
|
|
95a9e052de | ||
|
|
5c7777ff0f | ||
|
|
d223f49fbc | ||
|
|
e5c0e18751 | ||
|
|
5f74ed75e7 | ||
|
|
17fbab110c | ||
|
|
02ec70e290 | ||
|
|
5118f08d79 | ||
|
|
e565b75032 | ||
|
|
db9c0480ef | ||
|
|
10f5bc9be7 | ||
|
|
548ef00291 | ||
|
|
93806cd522 | ||
|
|
1a3a035404 | ||
|
|
6d94599977 | ||
|
|
c639bf0b19 | ||
|
|
514e483bc3 | ||
|
|
7604762013 | ||
|
|
f81855349a | ||
|
|
1455988efb | ||
|
|
d2f14b2951 | ||
|
|
73c79dbd41 | ||
|
|
0d7ff8ebd9 | ||
|
|
05166d0999 | ||
|
|
0e3322b5da | ||
|
|
a7d8b9a068 | ||
|
|
b31e298df4 | ||
|
|
a73b877c5b | ||
|
|
68e1d055dd | ||
|
|
aca92df19b | ||
|
|
560ad581ad | ||
|
|
fe2a91ae11 | ||
|
|
cd1507620f | ||
|
|
7ee7848a96 | ||
|
|
be7b19d587 | ||
|
|
16f5bbc20a | ||
|
|
8a27cff8c0 | ||
|
|
d43f05224d | ||
|
|
96492483ee | ||
|
|
194d8a3052 | ||
|
|
d500a44ff3 | ||
|
|
faa6a392e4 | ||
|
|
e33fa63243 | ||
|
|
d7f669dd7c | ||
|
|
993e48cab2 | ||
|
|
9762c61b4d | ||
|
|
d8803b309d | ||
|
|
f9a55e3728 | ||
|
|
a63fd6abb9 | ||
|
|
eff2a2afcf | ||
|
|
5cdad6ab86 | ||
|
|
30ca00d2c4 | ||
|
|
fbf8ed4140 | ||
|
|
64d68b4f08 | ||
|
|
91f7253ae1 | ||
|
|
06c8080664 | ||
|
|
b7da34a5d2 | ||
|
|
a972b77dc2 | ||
|
|
d27de1b111 | ||
|
|
d2cda84383 | ||
|
|
af1b017003 | ||
|
|
556f90ec28 | ||
|
|
22f238706c | ||
|
|
906afefbf3 | ||
|
|
38c36ff145 | ||
|
|
9ea0117dc4 | ||
|
|
4f81953338 | ||
|
|
ffc6d6325d | ||
|
|
6d46698494 | ||
|
|
b54dcafa80 | ||
|
|
ac0f13798b | ||
|
|
51771694cd | ||
|
|
9232991e25 | ||
|
|
71dc347582 | ||
|
|
31b18a8c8b | ||
|
|
d92e4c5663 | ||
|
|
300f0ddac5 | ||
|
|
77cf621f15 | ||
|
|
5c824cc24e | ||
|
|
3fd5250c0d | ||
|
|
8de70b1952 | ||
|
|
35808debae | ||
|
|
685d105739 | ||
|
|
43d5e89fac | ||
|
|
88a71eca72 | ||
|
|
b4983fdcae | ||
|
|
16a05316b2 | ||
|
|
1dda441b85 | ||
|
|
5cf826c73a | ||
|
|
9a5c64481e | ||
|
|
6de09a5eba | ||
|
|
03645acf4f | ||
|
|
c1e2a6c44c | ||
|
|
b3e7b7539e | ||
|
|
fdbbd8b383 | ||
|
|
70d1d71612 | ||
|
|
4bfc794a37 | ||
|
|
8a1f8d1a9a | ||
|
|
b05c1cafcd | ||
|
|
3be01a83ab | ||
|
|
26efca80d7 | ||
|
|
5fb3ac5937 | ||
|
|
9274f70fec | ||
|
|
78bdb26296 | ||
|
|
3132e9f595 | ||
|
|
b9e4dfbd40 | ||
|
|
2e80a09184 | ||
|
|
49cddea10b | ||
|
|
be3f6a2ca0 | ||
|
|
88d3261bc2 | ||
|
|
e5816b024f | ||
|
|
9cdc726dc1 | ||
|
|
e196cb1178 |
3
.codespellrc
Normal file
3
.codespellrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
[codespell]
|
||||||
|
ignore-words-list = fils, FILS, SME, assertIn, OCE, clen, aci, ELL, sav, ths
|
||||||
|
skip = build-aux, linux, autom4te.cache, aclocal.m4, AUTHORS, libtool, configure*, *.5, ell
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -66,6 +66,9 @@ unit/test-p2p
|
|||||||
unit/test-band
|
unit/test-band
|
||||||
unit/test-dpp
|
unit/test-dpp
|
||||||
unit/test-json
|
unit/test-json
|
||||||
|
unit/test-nl80211util
|
||||||
|
unit/test-pmksa
|
||||||
|
unit/test-storage
|
||||||
unit/cert-*.pem
|
unit/cert-*.pem
|
||||||
unit/cert-*.csr
|
unit/cert-*.csr
|
||||||
unit/cert-*.srl
|
unit/cert-*.srl
|
||||||
|
|||||||
79
ChangeLog
79
ChangeLog
@ -1,3 +1,82 @@
|
|||||||
|
ver 3.10:
|
||||||
|
Fix issue with handling neighbor report on BSS TM request.
|
||||||
|
Fix issue with handling deauth and FT association failure.
|
||||||
|
Fix issue with handling roaming and old frequencies.
|
||||||
|
|
||||||
|
ver 3.9:
|
||||||
|
Fix issue with Access Point mode and frequency unlocking.
|
||||||
|
Fix issue with network configuration and BSS retry logic.
|
||||||
|
Fix issue with handling busy notification from Access Point.
|
||||||
|
Fix issue with handling P-192, P-224 and P-521 for SAE.
|
||||||
|
|
||||||
|
ver 3.8:
|
||||||
|
Fix issue with handling unit tests and missing kernel features.
|
||||||
|
|
||||||
|
ver 3.7:
|
||||||
|
Fix issue with handling length of EncryptedSecurity.
|
||||||
|
Fix issue with handling empty affinities lists.
|
||||||
|
Fix issue with handling survey scanning results.
|
||||||
|
Fix issue with handling duplicate values in DPP URI.
|
||||||
|
|
||||||
|
ver 3.6:
|
||||||
|
Fix issue with handling blacklisting and roaming requests.
|
||||||
|
Fix issue with handling CQM thresholds for FullMAC devices.
|
||||||
|
Add support for PMKSA when using FullMAC devices.
|
||||||
|
|
||||||
|
ver 3.5:
|
||||||
|
Add support for option to disable blacklist handling.
|
||||||
|
Add support for option to disable SAE for broken drivers.
|
||||||
|
|
||||||
|
ver 3.4:
|
||||||
|
Add support for the Test Anything Protocol.
|
||||||
|
|
||||||
|
ver 3.3:
|
||||||
|
Fix issue with handling External Authentication.
|
||||||
|
|
||||||
|
ver 3.2:
|
||||||
|
Fix issue with GCC 15 and -std=c23 build errors.
|
||||||
|
Add support for using PMKSA over SAE if available.
|
||||||
|
Add support for HighUtilization/StationCount thresholds.
|
||||||
|
Add support for disabling Multicast RX option.
|
||||||
|
|
||||||
|
ver 3.1:
|
||||||
|
Fix issue with handling OWE transition BSS selection.
|
||||||
|
Fix issue with handling oper class 136 starting frequency.
|
||||||
|
|
||||||
|
ver 3.0:
|
||||||
|
Fix issue with handling alpha2 code for United Kingdom.
|
||||||
|
Fix issue with handling empty TX/RX bitrate attributes.
|
||||||
|
Fix issue with handling RSSI polling fallback workaround.
|
||||||
|
Fix issue with handling harmless cloned information elements.
|
||||||
|
Add experimental support for External Authentication feature.
|
||||||
|
|
||||||
|
ver 2.22:
|
||||||
|
Fix issue with handling the Affinities property.
|
||||||
|
Fix issue with handling ConnectedAccessPoint signal when roaming.
|
||||||
|
|
||||||
|
ver 2.21:
|
||||||
|
Fix issue with pending scan requests after regdom update.
|
||||||
|
Fix issue with handling the rearming of the roaming timeout.
|
||||||
|
Fix issue with survey request and externally triggered scans.
|
||||||
|
Fix issue with RSSI fallback when setting CQM threshold fails.
|
||||||
|
Fix issue with FT-over-Air without offchannel support.
|
||||||
|
Add support for per station Affinities property.
|
||||||
|
|
||||||
|
ver 2.20:
|
||||||
|
Fix issue with PKEX timeout and number of frequencies used.
|
||||||
|
Fix issue with handling logic for handshake failures.
|
||||||
|
Fix issue with handling ConnectedAccessPoint signal.
|
||||||
|
|
||||||
|
ver 2.19:
|
||||||
|
Fix issue with handling flush flag for external scans.
|
||||||
|
Fix issue with handling SNR calculation in ranking.
|
||||||
|
|
||||||
|
ver 2.18:
|
||||||
|
Fix issue with handling BSS with invalid HE capabilities.
|
||||||
|
Fix issue with neighbor reports with invalid country codes.
|
||||||
|
Fix issue with EAP-TTLS Start packets with L flag set.
|
||||||
|
Add support for enabling SAE for AP mode operation.
|
||||||
|
|
||||||
ver 2.17:
|
ver 2.17:
|
||||||
Fix issue with handling deauthenticate on disconnect.
|
Fix issue with handling deauthenticate on disconnect.
|
||||||
Fix issue with handling of rate estimation errors.
|
Fix issue with handling of rate estimation errors.
|
||||||
|
|||||||
45
Makefile.am
45
Makefile.am
@ -64,12 +64,16 @@ ell_headers = ell/util.h \
|
|||||||
ell/acd.h \
|
ell/acd.h \
|
||||||
ell/cleanup.h \
|
ell/cleanup.h \
|
||||||
ell/netconfig.h \
|
ell/netconfig.h \
|
||||||
ell/sysctl.h
|
ell/sysctl.h \
|
||||||
|
ell/notifylist.h \
|
||||||
|
ell/minheap.h
|
||||||
|
|
||||||
ell_sources = ell/private.h \
|
ell_sources = ell/private.h \
|
||||||
ell/missing.h \
|
ell/missing.h \
|
||||||
ell/util.c \
|
ell/util.c \
|
||||||
|
ell/test-private.h \
|
||||||
ell/test.c \
|
ell/test.c \
|
||||||
|
ell/test-dbus.c \
|
||||||
ell/strv.c \
|
ell/strv.c \
|
||||||
ell/utf8.c \
|
ell/utf8.c \
|
||||||
ell/queue.c \
|
ell/queue.c \
|
||||||
@ -145,7 +149,9 @@ ell_sources = ell/private.h \
|
|||||||
ell/dhcp6-transport.c \
|
ell/dhcp6-transport.c \
|
||||||
ell/acd.c \
|
ell/acd.c \
|
||||||
ell/netconfig.c \
|
ell/netconfig.c \
|
||||||
ell/sysctl.c
|
ell/sysctl.c \
|
||||||
|
ell/notifylist.c \
|
||||||
|
ell/minheap.c
|
||||||
|
|
||||||
ell_shared = ell/useful.h ell/asn1-private.h
|
ell_shared = ell/useful.h ell/asn1-private.h
|
||||||
|
|
||||||
@ -212,7 +218,8 @@ eap_sources = src/eap.c src/eap.h src/eap-private.h \
|
|||||||
if DAEMON
|
if DAEMON
|
||||||
libexec_PROGRAMS += src/iwd
|
libexec_PROGRAMS += src/iwd
|
||||||
|
|
||||||
src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h src/missing.h \
|
src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h \
|
||||||
|
src/missing.h src/defs.h \
|
||||||
src/netdev.h src/netdev.c \
|
src/netdev.h src/netdev.c \
|
||||||
src/wiphy.h src/wiphy.c \
|
src/wiphy.h src/wiphy.c \
|
||||||
src/device.c \
|
src/device.c \
|
||||||
@ -265,6 +272,10 @@ src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h src/missing.h \
|
|||||||
src/dpp-util.h src/dpp-util.c \
|
src/dpp-util.h src/dpp-util.c \
|
||||||
src/json.h src/json.c \
|
src/json.h src/json.c \
|
||||||
src/dpp.c \
|
src/dpp.c \
|
||||||
|
src/udev.c \
|
||||||
|
src/pmksa.h src/pmksa.c \
|
||||||
|
src/vendor_quirks.h \
|
||||||
|
src/vendor_quirks.c \
|
||||||
$(eap_sources) \
|
$(eap_sources) \
|
||||||
$(builtin_sources)
|
$(builtin_sources)
|
||||||
|
|
||||||
@ -316,6 +327,7 @@ client_iwctl_SOURCES = client/main.c \
|
|||||||
client/daemon.c client/daemon.h \
|
client/daemon.c client/daemon.h \
|
||||||
client/dpp.c client/dpp-pkex.c \
|
client/dpp.c client/dpp-pkex.c \
|
||||||
client/station-debug.c \
|
client/station-debug.c \
|
||||||
|
client/bss.c \
|
||||||
src/util.c src/util.h \
|
src/util.c src/util.h \
|
||||||
src/band.c src/band.h
|
src/band.c src/band.h
|
||||||
|
|
||||||
@ -430,7 +442,8 @@ unit_tests += unit/test-cmac-aes \
|
|||||||
unit/test-ie unit/test-util unit/test-ssid-security \
|
unit/test-ie unit/test-util unit/test-ssid-security \
|
||||||
unit/test-arc4 unit/test-wsc unit/test-eap-mschapv2 \
|
unit/test-arc4 unit/test-wsc unit/test-eap-mschapv2 \
|
||||||
unit/test-eap-sim unit/test-sae unit/test-p2p unit/test-band \
|
unit/test-eap-sim unit/test-sae unit/test-p2p unit/test-band \
|
||||||
unit/test-dpp unit/test-json
|
unit/test-dpp unit/test-json unit/test-nl80211util \
|
||||||
|
unit/test-pmksa unit/test-storage
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if CLIENT
|
if CLIENT
|
||||||
@ -449,6 +462,7 @@ unit_test_eap_sim_SOURCES = unit/test-eap-sim.c \
|
|||||||
src/eapol.h src/eapol.c \
|
src/eapol.h src/eapol.c \
|
||||||
src/eapolutil.h src/eapolutil.c \
|
src/eapolutil.h src/eapolutil.c \
|
||||||
src/handshake.h src/handshake.c \
|
src/handshake.h src/handshake.c \
|
||||||
|
src/pmksa.h src/pmksa.c \
|
||||||
src/eap.h src/eap.c src/eap-private.h \
|
src/eap.h src/eap.c src/eap-private.h \
|
||||||
src/util.h src/util.c \
|
src/util.h src/util.c \
|
||||||
src/simauth.h src/simauth.c \
|
src/simauth.h src/simauth.c \
|
||||||
@ -508,6 +522,7 @@ unit_test_eapol_SOURCES = unit/test-eapol.c \
|
|||||||
src/eapol.h src/eapol.c \
|
src/eapol.h src/eapol.c \
|
||||||
src/eapolutil.h src/eapolutil.c \
|
src/eapolutil.h src/eapolutil.c \
|
||||||
src/handshake.h src/handshake.c \
|
src/handshake.h src/handshake.c \
|
||||||
|
src/pmksa.h src/pmksa.c \
|
||||||
src/eap.h src/eap.c src/eap-private.h \
|
src/eap.h src/eap.c src/eap-private.h \
|
||||||
src/eap-tls.c src/eap-ttls.c \
|
src/eap-tls.c src/eap-ttls.c \
|
||||||
src/eap-md5.c src/util.c \
|
src/eap-md5.c src/util.c \
|
||||||
@ -538,6 +553,7 @@ unit_test_wsc_SOURCES = unit/test-wsc.c src/wscutil.h src/wscutil.c \
|
|||||||
src/eapol.h src/eapol.c \
|
src/eapol.h src/eapol.c \
|
||||||
src/eapolutil.h src/eapolutil.c \
|
src/eapolutil.h src/eapolutil.c \
|
||||||
src/handshake.h src/handshake.c \
|
src/handshake.h src/handshake.c \
|
||||||
|
src/pmksa.h src/pmksa.c \
|
||||||
src/eap.h src/eap.c src/eap-private.h \
|
src/eap.h src/eap.c src/eap-private.h \
|
||||||
src/util.h src/util.c \
|
src/util.h src/util.c \
|
||||||
src/erp.h src/erp.c \
|
src/erp.h src/erp.c \
|
||||||
@ -556,6 +572,7 @@ unit_test_sae_SOURCES = unit/test-sae.c \
|
|||||||
src/crypto.h src/crypto.c \
|
src/crypto.h src/crypto.c \
|
||||||
src/ie.h src/ie.c \
|
src/ie.h src/ie.c \
|
||||||
src/handshake.h src/handshake.c \
|
src/handshake.h src/handshake.c \
|
||||||
|
src/pmksa.h src/pmksa.c \
|
||||||
src/erp.h src/erp.c \
|
src/erp.h src/erp.c \
|
||||||
src/band.h src/band.c \
|
src/band.h src/band.c \
|
||||||
src/util.h src/util.c \
|
src/util.h src/util.c \
|
||||||
@ -579,6 +596,22 @@ unit_test_dpp_LDADD = $(ell_ldadd)
|
|||||||
|
|
||||||
unit_test_json_SOURCES = unit/test-json.c src/json.h src/json.c shared/jsmn.h
|
unit_test_json_SOURCES = unit/test-json.c src/json.h src/json.c shared/jsmn.h
|
||||||
unit_test_json_LDADD = $(ell_ldadd)
|
unit_test_json_LDADD = $(ell_ldadd)
|
||||||
|
|
||||||
|
unit_test_nl80211util_SOURCES = unit/test-nl80211util.c \
|
||||||
|
src/nl80211util.h src/nl80211util.c \
|
||||||
|
src/band.h src/band.c \
|
||||||
|
src/ie.h src/ie.c \
|
||||||
|
src/util.h src/util.c
|
||||||
|
unit_test_nl80211util_LDADD = $(ell_ldadd)
|
||||||
|
|
||||||
|
unit_test_pmksa_SOURCES = unit/test-pmksa.c src/pmksa.c src/pmksa.h \
|
||||||
|
src/module.h src/util.h
|
||||||
|
unit_test_pmksa_LDADD = $(ell_ldadd)
|
||||||
|
|
||||||
|
unit_test_storage_SOURCES = unit/test-storage.c src/storage.c src/storage.h \
|
||||||
|
src/crypto.c src/crypto.h \
|
||||||
|
src/common.c src/common.h
|
||||||
|
unit_test_storage_LDADD = $(ell_ldadd)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if CLIENT
|
if CLIENT
|
||||||
@ -594,6 +627,9 @@ unit_test_client_SOURCES = unit/test-client.c \
|
|||||||
unit_test_client_LDADD = $(ell_ldadd) $(client_ldadd)
|
unit_test_client_LDADD = $(ell_ldadd) $(client_ldadd)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) \
|
||||||
|
$(top_srcdir)/build-aux/tap-driver.sh
|
||||||
|
|
||||||
TESTS = $(unit_tests)
|
TESTS = $(unit_tests)
|
||||||
|
|
||||||
EXTRA_DIST = src/genbuiltin src/iwd.service.in src/net.connman.iwd.service \
|
EXTRA_DIST = src/genbuiltin src/iwd.service.in src/net.connman.iwd.service \
|
||||||
@ -710,6 +746,7 @@ ell/internal: Makefile
|
|||||||
done > $@
|
done > $@
|
||||||
|
|
||||||
ell/ell.h: Makefile
|
ell/ell.h: Makefile
|
||||||
|
$(AM_V_at)$(MKDIR_P) ell
|
||||||
$(AM_V_at)echo -n > $@
|
$(AM_V_at)echo -n > $@
|
||||||
$(AM_V_GEN)for f in $(ell_headers) ; do \
|
$(AM_V_GEN)for f in $(ell_headers) ; do \
|
||||||
echo "#include <$$f>" >> $@ ; \
|
echo "#include <$$f>" >> $@ ; \
|
||||||
|
|||||||
4
TODO
4
TODO
@ -110,7 +110,7 @@ Wireless monitor
|
|||||||
|
|
||||||
- Subscribe to all nl80211 multicast groups at startup
|
- Subscribe to all nl80211 multicast groups at startup
|
||||||
|
|
||||||
It seems the nlmon packets are limited to actual subscribed mutlicast
|
It seems the nlmon packets are limited to actual subscribed multicast
|
||||||
groups. To get a complete picture of all the nl80211 commands and
|
groups. To get a complete picture of all the nl80211 commands and
|
||||||
events, it is required that iwmon adds membership to all multicast
|
events, it is required that iwmon adds membership to all multicast
|
||||||
groups that the nl80211 lists.
|
groups that the nl80211 lists.
|
||||||
@ -234,7 +234,7 @@ Wireless daemon
|
|||||||
|
|
||||||
- Implement Enrollee Session Overlap Detection after WSC Protocol Run
|
- Implement Enrollee Session Overlap Detection after WSC Protocol Run
|
||||||
|
|
||||||
WSC Best Practices v2.0.1, Section 3.15 describes an enhacement to detect
|
WSC Best Practices v2.0.1, Section 3.15 describes an enhancement to detect
|
||||||
PBC session overlaps. The Enrollee is asked to perform an extra scan without
|
PBC session overlaps. The Enrollee is asked to perform an extra scan without
|
||||||
the PBC request in the ProbeRequest frames after EAP-WSC completes
|
the PBC request in the ProbeRequest frames after EAP-WSC completes
|
||||||
successfully. If another AP in PBC mode is found, then a SessionOverlap
|
successfully. If another AP in PBC mode is found, then a SessionOverlap
|
||||||
|
|||||||
156
autotests/testAPRoam/bad_neighbor_report_test.py
Normal file
156
autotests/testAPRoam/bad_neighbor_report_test.py
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.append('../util')
|
||||||
|
import iwd
|
||||||
|
from iwd import IWD
|
||||||
|
from iwd import NetworkType
|
||||||
|
|
||||||
|
from hostapd import HostapdCLI
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
def initial_connection(self):
|
||||||
|
ordered_network = self.device.get_ordered_network('TestAPRoam')
|
||||||
|
|
||||||
|
self.assertEqual(ordered_network.type, NetworkType.psk)
|
||||||
|
|
||||||
|
condition = 'not obj.connected'
|
||||||
|
self.wd.wait_for_object_condition(ordered_network.network_object, condition)
|
||||||
|
|
||||||
|
self.device.connect_bssid(self.bss_hostapd[0].bssid)
|
||||||
|
|
||||||
|
condition = 'obj.state == DeviceState.connected'
|
||||||
|
self.wd.wait_for_object_condition(self.device, condition)
|
||||||
|
|
||||||
|
self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED')
|
||||||
|
|
||||||
|
self.assertFalse(self.bss_hostapd[1].list_sta())
|
||||||
|
|
||||||
|
def test_full_scan(self):
|
||||||
|
"""
|
||||||
|
Tests that IWD first tries a limited scan, then a full scan after
|
||||||
|
an AP directed roam. After the full scan yields no results IWD
|
||||||
|
should stop trying to roam.
|
||||||
|
"""
|
||||||
|
self.initial_connection()
|
||||||
|
|
||||||
|
# Disable other APs, so the scans come up empty
|
||||||
|
self.bss_hostapd[1].disable()
|
||||||
|
self.bss_hostapd[2].disable()
|
||||||
|
|
||||||
|
# Send a bad candidate list with the BSS TM request which contains a
|
||||||
|
# channel with no AP operating on it.
|
||||||
|
self.bss_hostapd[0].send_bss_transition(
|
||||||
|
self.device.address,
|
||||||
|
[(self.bss_hostapd[1].bssid, "8f0000005105060603000000")]
|
||||||
|
)
|
||||||
|
self.device.wait_for_event("roam-scan-triggered")
|
||||||
|
self.device.wait_for_event("no-roam-candidates")
|
||||||
|
# IWD should then trigger a full scan
|
||||||
|
self.device.wait_for_event("full-roam-scan")
|
||||||
|
self.device.wait_for_event("no-roam-candidates", timeout=30)
|
||||||
|
|
||||||
|
# IWD should not trigger a roam again after the above 2 failures.
|
||||||
|
with self.assertRaises(TimeoutError):
|
||||||
|
self.device.wait_for_event("roam-scan-triggered", timeout=60)
|
||||||
|
|
||||||
|
def test_bad_candidate_list(self):
|
||||||
|
"""
|
||||||
|
Tests behavior when the AP sends a candidate list but the scan
|
||||||
|
finds no BSS's. IWD should fall back to a full scan after.
|
||||||
|
"""
|
||||||
|
self.initial_connection()
|
||||||
|
|
||||||
|
# Send a bad candidate list with the BSS TM request which contains a
|
||||||
|
# channel with no AP operating on it.
|
||||||
|
self.bss_hostapd[0].send_bss_transition(
|
||||||
|
self.device.address,
|
||||||
|
[(self.bss_hostapd[1].bssid, "8f0000005105060603000000")]
|
||||||
|
)
|
||||||
|
self.device.wait_for_event("roam-scan-triggered")
|
||||||
|
self.device.wait_for_event("no-roam-candidates")
|
||||||
|
# IWD should then trigger a full scan
|
||||||
|
self.device.wait_for_event("full-roam-scan")
|
||||||
|
self.device.wait_for_event("roaming", timeout=30)
|
||||||
|
self.device.wait_for_event("connected")
|
||||||
|
|
||||||
|
def test_bad_neighbor_report(self):
|
||||||
|
"""
|
||||||
|
Tests behavior when the AP sends no candidate list. IWD should
|
||||||
|
request a neighbor report. If the limited scan yields no BSS's IWD
|
||||||
|
should fall back to a full scan.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Set a bad neighbor (channel that no AP is on) to force the limited
|
||||||
|
# roam scan to fail
|
||||||
|
self.bss_hostapd[0].set_neighbor(
|
||||||
|
self.bss_hostapd[1].bssid,
|
||||||
|
"TestAPRoam",
|
||||||
|
'%s8f000000%s%s060603000000' % (self.bss_hostapd[1].bssid.replace(':', ''), "51", "0b")
|
||||||
|
)
|
||||||
|
|
||||||
|
self.initial_connection()
|
||||||
|
|
||||||
|
self.bss_hostapd[0].send_bss_transition(self.device.address, [])
|
||||||
|
self.device.wait_for_event("roam-scan-triggered")
|
||||||
|
# The AP will have sent a neighbor report with a single BSS but on
|
||||||
|
# channel 11 which no AP is on. This should result in a limited scan
|
||||||
|
# picking up no candidates.
|
||||||
|
self.device.wait_for_event("no-roam-candidates", timeout=30)
|
||||||
|
# IWD should then trigger a full scan
|
||||||
|
self.device.wait_for_event("full-roam-scan")
|
||||||
|
self.device.wait_for_event("roaming", timeout=30)
|
||||||
|
self.device.wait_for_event("connected")
|
||||||
|
|
||||||
|
def test_ignore_candidate_list_quirk(self):
|
||||||
|
"""
|
||||||
|
Tests that IWD ignores the candidate list sent by the AP since its
|
||||||
|
OUI indicates it should be ignored.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Set the OUI so the candidate list should be ignored
|
||||||
|
for hapd in self.bss_hostapd:
|
||||||
|
hapd.set_value('vendor_elements', 'dd0400180a01')
|
||||||
|
|
||||||
|
self.initial_connection()
|
||||||
|
|
||||||
|
# Send with a candidate list (should be ignored)
|
||||||
|
self.bss_hostapd[0].send_bss_transition(
|
||||||
|
self.device.address,
|
||||||
|
[(self.bss_hostapd[1].bssid, "8f0000005105060603000000")]
|
||||||
|
)
|
||||||
|
# IWD should ignore the list and trigger a full scan since we have not
|
||||||
|
# set any neighbors
|
||||||
|
self.device.wait_for_event("full-roam-scan")
|
||||||
|
self.device.wait_for_event("roaming", timeout=30)
|
||||||
|
self.device.wait_for_event("connected")
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.wd = IWD(True)
|
||||||
|
|
||||||
|
devices = self.wd.list_devices(1)
|
||||||
|
self.device = devices[0]
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.wd = None
|
||||||
|
self.device = None
|
||||||
|
|
||||||
|
for hapd in self.bss_hostapd:
|
||||||
|
hapd.reload()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
IWD.copy_to_storage('TestAPRoam.psk')
|
||||||
|
|
||||||
|
cls.bss_hostapd = [ HostapdCLI(config='ssid1.conf'),
|
||||||
|
HostapdCLI(config='ssid2.conf'),
|
||||||
|
HostapdCLI(config='ssid3.conf') ]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
IWD.clear_storage()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main(exit=True)
|
||||||
@ -11,52 +11,58 @@ from iwd import NetworkType
|
|||||||
from hostapd import HostapdCLI
|
from hostapd import HostapdCLI
|
||||||
|
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
|
def initial_connection(self):
|
||||||
def validate(self, expect_roam=True):
|
ordered_network = self.device.get_ordered_network('TestAPRoam')
|
||||||
wd = IWD()
|
|
||||||
|
|
||||||
devices = wd.list_devices(1)
|
|
||||||
device = devices[0]
|
|
||||||
|
|
||||||
ordered_network = device.get_ordered_network('TestAPRoam')
|
|
||||||
|
|
||||||
self.assertEqual(ordered_network.type, NetworkType.psk)
|
self.assertEqual(ordered_network.type, NetworkType.psk)
|
||||||
|
|
||||||
condition = 'not obj.connected'
|
condition = 'not obj.connected'
|
||||||
wd.wait_for_object_condition(ordered_network.network_object, condition)
|
self.wd.wait_for_object_condition(ordered_network.network_object, condition)
|
||||||
|
|
||||||
device.connect_bssid(self.bss_hostapd[0].bssid)
|
self.device.connect_bssid(self.bss_hostapd[0].bssid)
|
||||||
|
|
||||||
condition = 'obj.state == DeviceState.connected'
|
condition = 'obj.state == DeviceState.connected'
|
||||||
wd.wait_for_object_condition(device, condition)
|
self.wd.wait_for_object_condition(self.device, condition)
|
||||||
|
|
||||||
self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED')
|
self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED')
|
||||||
|
|
||||||
self.assertFalse(self.bss_hostapd[1].list_sta())
|
self.assertFalse(self.bss_hostapd[1].list_sta())
|
||||||
|
|
||||||
self.bss_hostapd[0].send_bss_transition(device.address,
|
def validate_roam(self, from_bss, to_bss, expect_roam=True):
|
||||||
[(self.bss_hostapd[1].bssid, '8f0000005102060603000000')],
|
from_bss.send_bss_transition(self.device.address,
|
||||||
|
self.neighbor_list,
|
||||||
disassoc_imminent=expect_roam)
|
disassoc_imminent=expect_roam)
|
||||||
|
|
||||||
if expect_roam:
|
if expect_roam:
|
||||||
from_condition = 'obj.state == DeviceState.roaming'
|
from_condition = 'obj.state == DeviceState.roaming'
|
||||||
to_condition = 'obj.state == DeviceState.connected'
|
to_condition = 'obj.state == DeviceState.connected'
|
||||||
wd.wait_for_object_change(device, from_condition, to_condition)
|
self.wd.wait_for_object_change(self.device, from_condition, to_condition)
|
||||||
|
|
||||||
self.bss_hostapd[1].wait_for_event('AP-STA-CONNECTED %s' % device.address)
|
to_bss.wait_for_event('AP-STA-CONNECTED %s' % self.device.address)
|
||||||
else:
|
else:
|
||||||
device.wait_for_event("no-roam-candidates")
|
self.device.wait_for_event("no-roam-candidates")
|
||||||
|
|
||||||
device.disconnect()
|
|
||||||
|
|
||||||
condition = 'not obj.connected'
|
|
||||||
wd.wait_for_object_condition(ordered_network.network_object, condition)
|
|
||||||
|
|
||||||
def test_disassoc_imminent(self):
|
def test_disassoc_imminent(self):
|
||||||
self.validate(expect_roam=True)
|
self.initial_connection()
|
||||||
|
self.validate_roam(self.bss_hostapd[0], self.bss_hostapd[1])
|
||||||
|
|
||||||
def test_no_candidates(self):
|
def test_no_candidates(self):
|
||||||
self.validate(expect_roam=False)
|
self.initial_connection()
|
||||||
|
# We now have BSS0 roam blacklisted
|
||||||
|
self.validate_roam(self.bss_hostapd[0], self.bss_hostapd[1])
|
||||||
|
# Try and trigger another roam back, which shouldn't happen since now
|
||||||
|
# both BSS's are roam blacklisted
|
||||||
|
self.validate_roam(self.bss_hostapd[1], self.bss_hostapd[0], expect_roam=False)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.wd = IWD(True)
|
||||||
|
|
||||||
|
devices = self.wd.list_devices(1)
|
||||||
|
self.device = devices[0]
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.wd = None
|
||||||
|
self.device = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
@ -65,6 +71,10 @@ class Test(unittest.TestCase):
|
|||||||
cls.bss_hostapd = [ HostapdCLI(config='ssid1.conf'),
|
cls.bss_hostapd = [ HostapdCLI(config='ssid1.conf'),
|
||||||
HostapdCLI(config='ssid2.conf'),
|
HostapdCLI(config='ssid2.conf'),
|
||||||
HostapdCLI(config='ssid3.conf') ]
|
HostapdCLI(config='ssid3.conf') ]
|
||||||
|
cls.neighbor_list = [
|
||||||
|
(cls.bss_hostapd[0].bssid, "8f0000005101060603000000"),
|
||||||
|
(cls.bss_hostapd[1].bssid, "8f0000005102060603000000"),
|
||||||
|
]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def tearDownClass(cls):
|
def tearDownClass(cls):
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
[SETUP]
|
[SETUP]
|
||||||
num_radios=4
|
num_radios=4
|
||||||
|
hwsim_medium=true
|
||||||
|
start_iwd=false
|
||||||
|
|
||||||
[HOSTAPD]
|
[HOSTAPD]
|
||||||
rad0=ssid1.conf
|
rad0=ssid1.conf
|
||||||
|
|||||||
6
autotests/testAPRoam/main.conf.roaming
Normal file
6
autotests/testAPRoam/main.conf.roaming
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[General]
|
||||||
|
RoamThreshold=-72
|
||||||
|
CriticalRoamThreshold=-72
|
||||||
|
|
||||||
|
[Blacklist]
|
||||||
|
InitialAccessPointBusyTimeout=20
|
||||||
183
autotests/testAPRoam/roam_blacklist_test.py
Normal file
183
autotests/testAPRoam/roam_blacklist_test.py
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.append('../util')
|
||||||
|
import iwd
|
||||||
|
from iwd import IWD, IWD_CONFIG_DIR
|
||||||
|
from iwd import NetworkType
|
||||||
|
|
||||||
|
from hostapd import HostapdCLI
|
||||||
|
from hwsim import Hwsim
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
def validate_connected(self, hostapd):
|
||||||
|
ordered_network = self.device.get_ordered_network('TestAPRoam')
|
||||||
|
|
||||||
|
self.assertEqual(ordered_network.type, NetworkType.psk)
|
||||||
|
|
||||||
|
condition = 'not obj.connected'
|
||||||
|
self.wd.wait_for_object_condition(ordered_network.network_object, condition)
|
||||||
|
|
||||||
|
self.device.connect_bssid(hostapd.bssid)
|
||||||
|
|
||||||
|
condition = 'obj.state == DeviceState.connected'
|
||||||
|
self.wd.wait_for_object_condition(self.device, condition)
|
||||||
|
|
||||||
|
hostapd.wait_for_event('AP-STA-CONNECTED')
|
||||||
|
|
||||||
|
def validate_ap_roamed(self, from_hostapd, to_hostapd):
|
||||||
|
from_hostapd.send_bss_transition(
|
||||||
|
self.device.address, self.neighbor_list, disassoc_imminent=True
|
||||||
|
)
|
||||||
|
|
||||||
|
from_condition = 'obj.state == DeviceState.roaming'
|
||||||
|
to_condition = 'obj.state == DeviceState.connected'
|
||||||
|
self.wd.wait_for_object_change(self.device, from_condition, to_condition)
|
||||||
|
|
||||||
|
to_hostapd.wait_for_event('AP-STA-CONNECTED %s' % self.device.address)
|
||||||
|
|
||||||
|
self.device.wait_for_event("ap-roam-blacklist-added")
|
||||||
|
|
||||||
|
def test_roam_to_optimal_candidates(self):
|
||||||
|
# In this test IWD will naturally transition down the list after each
|
||||||
|
# BSS gets roam blacklisted. All BSS's are above the RSSI thresholds.
|
||||||
|
self.rule_ssid1.signal = -5000
|
||||||
|
self.rule_ssid2.signal = -6500
|
||||||
|
self.rule_ssid3.signal = -6900
|
||||||
|
|
||||||
|
# Connect to BSS0
|
||||||
|
self.validate_connected(self.bss_hostapd[0])
|
||||||
|
|
||||||
|
# AP directed roam to BSS1
|
||||||
|
self.validate_ap_roamed(self.bss_hostapd[0], self.bss_hostapd[1])
|
||||||
|
|
||||||
|
# AP directed roam to BSS2
|
||||||
|
self.validate_ap_roamed(self.bss_hostapd[1], self.bss_hostapd[2])
|
||||||
|
|
||||||
|
def test_avoiding_under_threshold_bss(self):
|
||||||
|
# In this test IWD will blacklist BSS0, then roam the BSS1. BSS1 will
|
||||||
|
# then tell IWD to roam, but it should go back to BSS0 since the only
|
||||||
|
# non-blacklisted BSS is under the roam threshold.
|
||||||
|
self.rule_ssid1.signal = -5000
|
||||||
|
self.rule_ssid2.signal = -6500
|
||||||
|
self.rule_ssid3.signal = -7300
|
||||||
|
|
||||||
|
# Connect to BSS0
|
||||||
|
self.validate_connected(self.bss_hostapd[0])
|
||||||
|
|
||||||
|
# AP directed roam to BSS1
|
||||||
|
self.validate_ap_roamed(self.bss_hostapd[0], self.bss_hostapd[1])
|
||||||
|
|
||||||
|
# AP directed roam, but IWD should choose BSS0 since BSS2 is -73dB
|
||||||
|
self.validate_ap_roamed(self.bss_hostapd[1], self.bss_hostapd[0])
|
||||||
|
|
||||||
|
def test_connect_to_roam_blacklisted_bss(self):
|
||||||
|
# In this test a BSS will be roam blacklisted, but all other options are
|
||||||
|
# below the RSSI threshold so IWD should roam back to the blacklisted
|
||||||
|
# BSS.
|
||||||
|
self.rule_ssid1.signal = -5000
|
||||||
|
self.rule_ssid2.signal = -8000
|
||||||
|
self.rule_ssid3.signal = -8500
|
||||||
|
|
||||||
|
# Connect to BSS0
|
||||||
|
self.validate_connected(self.bss_hostapd[0])
|
||||||
|
|
||||||
|
# AP directed roam, should connect to BSS1 as its the next best
|
||||||
|
self.validate_ap_roamed(self.bss_hostapd[0], self.bss_hostapd[1])
|
||||||
|
|
||||||
|
# Connected to BSS1, but the signal is bad, so IWD should try to roam
|
||||||
|
# again. BSS0 is still blacklisted, but its the only reasonable option
|
||||||
|
# since both BSS1 and BSS2 are below the set RSSI threshold (-72dB)
|
||||||
|
|
||||||
|
from_condition = 'obj.state == DeviceState.roaming'
|
||||||
|
to_condition = 'obj.state == DeviceState.connected'
|
||||||
|
self.wd.wait_for_object_change(self.device, from_condition, to_condition)
|
||||||
|
|
||||||
|
# IWD should have connected to BSS0, even though its roam blacklisted
|
||||||
|
self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED %s' % self.device.address)
|
||||||
|
|
||||||
|
def test_blacklist_during_roam_scan(self):
|
||||||
|
# Tests that an AP roam request mid-roam results in the AP still being
|
||||||
|
# blacklisted even though the request itself doesn't directly trigger
|
||||||
|
# a roam.
|
||||||
|
self.rule_ssid1.signal = -7300
|
||||||
|
self.rule_ssid2.signal = -7500
|
||||||
|
self.rule_ssid3.signal = -8500
|
||||||
|
|
||||||
|
# Connect to BSS0 under the roam threshold so IWD will immediately try
|
||||||
|
# roaming elsewhere
|
||||||
|
self.validate_connected(self.bss_hostapd[0])
|
||||||
|
|
||||||
|
self.device.wait_for_event("roam-scan-triggered")
|
||||||
|
|
||||||
|
self.bss_hostapd[0].send_bss_transition(
|
||||||
|
self.device.address, self.neighbor_list, disassoc_imminent=True
|
||||||
|
)
|
||||||
|
self.device.wait_for_event("ap-roam-blacklist-added")
|
||||||
|
|
||||||
|
# BSS0 should have gotten blacklisted even though IWD was mid-roam,
|
||||||
|
# causing IWD to choose BSS1 when it gets is results.
|
||||||
|
|
||||||
|
from_condition = 'obj.state == DeviceState.roaming'
|
||||||
|
to_condition = 'obj.state == DeviceState.connected'
|
||||||
|
self.wd.wait_for_object_change(self.device, from_condition, to_condition)
|
||||||
|
|
||||||
|
self.bss_hostapd[1].wait_for_event('AP-STA-CONNECTED %s' % self.device.address)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.wd = IWD(True)
|
||||||
|
|
||||||
|
devices = self.wd.list_devices(1)
|
||||||
|
self.device = devices[0]
|
||||||
|
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.wd = None
|
||||||
|
self.device = None
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
IWD.copy_to_storage("main.conf.roaming", IWD_CONFIG_DIR, "main.conf")
|
||||||
|
IWD.copy_to_storage('TestAPRoam.psk')
|
||||||
|
hwsim = Hwsim()
|
||||||
|
|
||||||
|
cls.bss_hostapd = [ HostapdCLI(config='ssid1.conf'),
|
||||||
|
HostapdCLI(config='ssid2.conf'),
|
||||||
|
HostapdCLI(config='ssid3.conf') ]
|
||||||
|
HostapdCLI.group_neighbors(*cls.bss_hostapd)
|
||||||
|
|
||||||
|
rad0 = hwsim.get_radio('rad0')
|
||||||
|
rad1 = hwsim.get_radio('rad1')
|
||||||
|
rad2 = hwsim.get_radio('rad2')
|
||||||
|
|
||||||
|
cls.neighbor_list = [
|
||||||
|
(cls.bss_hostapd[0].bssid, "8f0000005101060603000000"),
|
||||||
|
(cls.bss_hostapd[1].bssid, "8f0000005102060603000000"),
|
||||||
|
(cls.bss_hostapd[2].bssid, "8f0000005103060603000000"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
cls.rule_ssid1 = hwsim.rules.create()
|
||||||
|
cls.rule_ssid1.source = rad0.addresses[0]
|
||||||
|
cls.rule_ssid1.bidirectional = True
|
||||||
|
cls.rule_ssid1.enabled = True
|
||||||
|
|
||||||
|
cls.rule_ssid2 = hwsim.rules.create()
|
||||||
|
cls.rule_ssid2.source = rad1.addresses[0]
|
||||||
|
cls.rule_ssid2.bidirectional = True
|
||||||
|
cls.rule_ssid2.enabled = True
|
||||||
|
|
||||||
|
cls.rule_ssid3 = hwsim.rules.create()
|
||||||
|
cls.rule_ssid3.source = rad2.addresses[0]
|
||||||
|
cls.rule_ssid3.bidirectional = True
|
||||||
|
cls.rule_ssid3.enabled = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
IWD.clear_storage()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main(exit=True)
|
||||||
2
autotests/testAffinity/TestFT.psk
Normal file
2
autotests/testAffinity/TestFT.psk
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[Security]
|
||||||
|
Passphrase=EasilyGuessedPassword
|
||||||
41
autotests/testAffinity/ft-psk-ccmp-1.conf
Normal file
41
autotests/testAffinity/ft-psk-ccmp-1.conf
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
hw_mode=g
|
||||||
|
channel=1
|
||||||
|
ssid=TestFT
|
||||||
|
utf8_ssid=1
|
||||||
|
ctrl_interface=/var/run/hostapd
|
||||||
|
|
||||||
|
r1_key_holder=120000000001
|
||||||
|
nas_identifier=dummy1
|
||||||
|
|
||||||
|
wpa=2
|
||||||
|
# Can support WPA-PSK and FT-PSK (space separated list) and/or EAP at the same
|
||||||
|
# time but we want to force FT
|
||||||
|
wpa_key_mgmt=FT-PSK
|
||||||
|
wpa_pairwise=CCMP
|
||||||
|
wpa_passphrase=EasilyGuessedPassword
|
||||||
|
ieee80211w=0
|
||||||
|
rsn_preauth=1
|
||||||
|
rsn_preauth_interfaces=lo
|
||||||
|
disable_pmksa_caching=0
|
||||||
|
# Allow PMK cache to be shared opportunistically among configured interfaces
|
||||||
|
# and BSSes (i.e., all configurations within a single hostapd process).
|
||||||
|
okc=1
|
||||||
|
mobility_domain=1234
|
||||||
|
reassociation_deadline=60000
|
||||||
|
r0kh=12:00:00:00:00:01 dummy1 000102030405060708090a0b0c0d0e0f
|
||||||
|
r0kh=12:00:00:00:00:02 dummy2 000102030405060708090a0b0c0d0e0f
|
||||||
|
r1kh=12:00:00:00:00:01 00:00:00:00:00:01 000102030405060708090a0b0c0d0e0f
|
||||||
|
r1kh=12:00:00:00:00:02 00:00:00:00:00:02 000102030405060708090a0b0c0d0e0f
|
||||||
|
# Push mode only needed for 8021x, not PSK mode since msk already known
|
||||||
|
pmk_r1_push=0
|
||||||
|
# Allow locally generated FT response so we don't have to configure push/pull
|
||||||
|
# between BSSes running as separate hostapd processes as in the test-runner
|
||||||
|
# case. Only works with FT-PSK, otherwise brctl needs to be installed and
|
||||||
|
# CONFIG_BRIDGE enabled in the kernel.
|
||||||
|
ft_psk_generate_local=1
|
||||||
|
rkh_pull_timeout=50
|
||||||
|
ft_over_ds=0
|
||||||
|
ap_table_expiration_time=36000
|
||||||
|
ap_table_max_size=10
|
||||||
|
rrm_neighbor_report=1
|
||||||
|
ocv=1
|
||||||
41
autotests/testAffinity/ft-psk-ccmp-2.conf
Normal file
41
autotests/testAffinity/ft-psk-ccmp-2.conf
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
hw_mode=g
|
||||||
|
channel=2
|
||||||
|
ssid=TestFT
|
||||||
|
utf8_ssid=1
|
||||||
|
ctrl_interface=/var/run/hostapd
|
||||||
|
|
||||||
|
r1_key_holder=120000000002
|
||||||
|
nas_identifier=dummy2
|
||||||
|
|
||||||
|
wpa=2
|
||||||
|
# Can support WPA-PSK and FT-PSK (space separated list) and/or EAP at the same
|
||||||
|
# time but we want to force FT
|
||||||
|
wpa_key_mgmt=FT-PSK
|
||||||
|
wpa_pairwise=CCMP
|
||||||
|
wpa_passphrase=EasilyGuessedPassword
|
||||||
|
ieee80211w=0
|
||||||
|
rsn_preauth=1
|
||||||
|
rsn_preauth_interfaces=lo
|
||||||
|
disable_pmksa_caching=0
|
||||||
|
# Allow PMK cache to be shared opportunistically among configured interfaces
|
||||||
|
# and BSSes (i.e., all configurations within a single hostapd process).
|
||||||
|
okc=1
|
||||||
|
mobility_domain=1234
|
||||||
|
reassociation_deadline=60000
|
||||||
|
r0kh=12:00:00:00:00:01 dummy1 000102030405060708090a0b0c0d0e0f
|
||||||
|
r0kh=12:00:00:00:00:02 dummy2 000102030405060708090a0b0c0d0e0f
|
||||||
|
r1kh=12:00:00:00:00:01 00:00:00:00:00:01 000102030405060708090a0b0c0d0e0f
|
||||||
|
r1kh=12:00:00:00:00:02 00:00:00:00:00:02 000102030405060708090a0b0c0d0e0f
|
||||||
|
# Push mode only needed for 8021x, not PSK mode since msk already known
|
||||||
|
pmk_r1_push=0
|
||||||
|
# Allow locally generated FT response so we don't have to configure push/pull
|
||||||
|
# between BSSes running as separate hostapd processes as in the test-runner
|
||||||
|
# case. Only works with FT-PSK, otherwise brctl needs to be installed and
|
||||||
|
# CONFIG_BRIDGE enabled in the kernel.
|
||||||
|
ft_psk_generate_local=1
|
||||||
|
rkh_pull_timeout=50
|
||||||
|
ft_over_ds=0
|
||||||
|
ap_table_expiration_time=36000
|
||||||
|
ap_table_max_size=10
|
||||||
|
rrm_neighbor_report=1
|
||||||
|
ocv=1
|
||||||
8
autotests/testAffinity/hw.conf
Normal file
8
autotests/testAffinity/hw.conf
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[SETUP]
|
||||||
|
num_radios=3
|
||||||
|
start_iwd=0
|
||||||
|
hwsim_medium=yes
|
||||||
|
|
||||||
|
[HOSTAPD]
|
||||||
|
rad0=ft-psk-ccmp-1.conf
|
||||||
|
rad1=ft-psk-ccmp-2.conf
|
||||||
5
autotests/testAffinity/main.conf
Normal file
5
autotests/testAffinity/main.conf
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[Scan]
|
||||||
|
DisableMacAddressRandomization=true
|
||||||
|
|
||||||
|
[General]
|
||||||
|
RoamRetryInterval=1
|
||||||
216
autotests/testAffinity/test_set_affinity.py
Normal file
216
autotests/testAffinity/test_set_affinity.py
Normal file
@ -0,0 +1,216 @@
|
|||||||
|
#! /usr/bin/python3
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import sys, os
|
||||||
|
import dbus
|
||||||
|
|
||||||
|
sys.path.append('../util')
|
||||||
|
from config import ctx
|
||||||
|
import iwd
|
||||||
|
from iwd import IWD, IWDDBusAbstract
|
||||||
|
from iwd import NetworkType
|
||||||
|
from hwsim import Hwsim
|
||||||
|
from hostapd import HostapdCLI
|
||||||
|
|
||||||
|
#
|
||||||
|
# Separate client used to test DBus disconnects so we don't bring down the
|
||||||
|
# entire IWD python library
|
||||||
|
#
|
||||||
|
class AffinityClient(IWDDBusAbstract):
|
||||||
|
def __init__(self, device_path):
|
||||||
|
self._bus = dbus.bus.BusConnection(address_or_type=ctx.dbus_address)
|
||||||
|
self._station_prop_if = dbus.Interface(
|
||||||
|
self._bus.get_object(iwd.IWD_SERVICE, device_path),
|
||||||
|
iwd.DBUS_PROPERTIES)
|
||||||
|
|
||||||
|
def set(self, values):
|
||||||
|
self._station_prop_if.Set(iwd.IWD_STATION_INTERFACE, 'Affinities', dbus.Array([dbus.ObjectPath(v) for v in values], signature="o"))
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
self._bus.close()
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
def connect(self, device, hapd):
|
||||||
|
ordered_network = device.get_ordered_network('TestFT', full_scan=True)
|
||||||
|
|
||||||
|
self.assertEqual(ordered_network.type, NetworkType.psk)
|
||||||
|
|
||||||
|
condition = 'not obj.connected'
|
||||||
|
self.wd.wait_for_object_condition(ordered_network.network_object, condition)
|
||||||
|
|
||||||
|
device.connect_bssid(hapd.bssid)
|
||||||
|
|
||||||
|
condition = 'obj.state == DeviceState.connected'
|
||||||
|
self.wd.wait_for_object_condition(device, condition)
|
||||||
|
|
||||||
|
def test_set_affinity(self):
|
||||||
|
device = self.wd.list_devices(1)[0]
|
||||||
|
|
||||||
|
self.connect(device, self.bss_hostapd[0])
|
||||||
|
|
||||||
|
print(device.connected_bss)
|
||||||
|
|
||||||
|
device.affinities = [device.connected_bss]
|
||||||
|
|
||||||
|
# IWD should not attempt to roam
|
||||||
|
with self.assertRaises(TimeoutError):
|
||||||
|
device.wait_for_event("roam-scan-triggered")
|
||||||
|
|
||||||
|
device.affinities = []
|
||||||
|
device.wait_for_event("roam-scan-triggered")
|
||||||
|
|
||||||
|
def test_roam_below_critical(self):
|
||||||
|
device = self.wd.list_devices(1)[0]
|
||||||
|
|
||||||
|
self.connect(device, self.bss_hostapd[0])
|
||||||
|
|
||||||
|
device.affinities = [device.connected_bss]
|
||||||
|
|
||||||
|
# IWD should not attempt to roam
|
||||||
|
with self.assertRaises(TimeoutError):
|
||||||
|
device.wait_for_event("roam-scan-triggered")
|
||||||
|
|
||||||
|
# Lower signal past critical level
|
||||||
|
self.bss0_rule.signal = -9000
|
||||||
|
|
||||||
|
device.wait_for_event("roam-scan-triggered")
|
||||||
|
|
||||||
|
def test_error_conditions(self):
|
||||||
|
device = self.wd.list_devices(1)[0]
|
||||||
|
|
||||||
|
# Calling set while disconnected should fail
|
||||||
|
with self.assertRaises(iwd.NotConnectedEx):
|
||||||
|
device.affinities = ["/some/path"]
|
||||||
|
|
||||||
|
self.connect(device, self.bss_hostapd[0])
|
||||||
|
|
||||||
|
device.affinities = [device.connected_bss]
|
||||||
|
|
||||||
|
# An invalid path should fail
|
||||||
|
with self.assertRaises(iwd.InvalidArgumentsEx):
|
||||||
|
device.affinities = [device.connected_bss, "/an/invalid/path"]
|
||||||
|
|
||||||
|
def test_affinity_client_disconnect(self):
|
||||||
|
device = self.wd.list_devices(1)[0]
|
||||||
|
|
||||||
|
client = AffinityClient(device.device_path)
|
||||||
|
|
||||||
|
self.connect(device, self.bss_hostapd[0])
|
||||||
|
|
||||||
|
client.set([device.connected_bss])
|
||||||
|
|
||||||
|
with self.assertRaises(TimeoutError):
|
||||||
|
device.wait_for_event("roam-scan-triggered")
|
||||||
|
|
||||||
|
client._bus.close()
|
||||||
|
|
||||||
|
device.wait_for_event("roam-scan-triggered")
|
||||||
|
|
||||||
|
def test_affinity_client_reconnect_during_roam(self):
|
||||||
|
device = self.wd.list_devices(1)[0]
|
||||||
|
|
||||||
|
client = AffinityClient(device.device_path)
|
||||||
|
|
||||||
|
self.connect(device, self.bss_hostapd[0])
|
||||||
|
|
||||||
|
client.set([device.connected_bss])
|
||||||
|
|
||||||
|
# Lower signal past critical level
|
||||||
|
self.bss0_rule.signal = -9000
|
||||||
|
|
||||||
|
device.wait_for_event("roam-scan-triggered")
|
||||||
|
|
||||||
|
client.close()
|
||||||
|
del client
|
||||||
|
client = AffinityClient(device.device_path)
|
||||||
|
# setting here should get cleared after connecting
|
||||||
|
client.set([device.connected_bss])
|
||||||
|
|
||||||
|
device.wait_for_event("ft-authenticating")
|
||||||
|
device.wait_for_event("associating")
|
||||||
|
device.wait_for_event("connected")
|
||||||
|
|
||||||
|
# Affinity should be reset, and IWD should be trying to roam
|
||||||
|
device.wait_for_event("roam-scan-triggered")
|
||||||
|
|
||||||
|
def test_cleanup_with_connected_client(self):
|
||||||
|
device = self.wd.list_devices(1)[0]
|
||||||
|
|
||||||
|
client = AffinityClient(device.device_path)
|
||||||
|
|
||||||
|
self.connect(device, self.bss_hostapd[0])
|
||||||
|
|
||||||
|
client.set([device.connected_bss])
|
||||||
|
self.wd.stop()
|
||||||
|
|
||||||
|
def test_affinity_removed_after_roam(self):
|
||||||
|
device = self.wd.list_devices(1)[0]
|
||||||
|
|
||||||
|
self.connect(device, self.bss_hostapd[0])
|
||||||
|
|
||||||
|
device.affinities = [device.connected_bss]
|
||||||
|
|
||||||
|
# Lower signal past critical level
|
||||||
|
self.bss0_rule.signal = -9000
|
||||||
|
|
||||||
|
device.wait_for_event("roam-scan-triggered")
|
||||||
|
|
||||||
|
device.wait_for_event("ft-authenticating")
|
||||||
|
device.wait_for_event("associating")
|
||||||
|
device.wait_for_event("connected")
|
||||||
|
|
||||||
|
self.assertEqual(device.affinities, [])
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" down')
|
||||||
|
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" down')
|
||||||
|
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" up')
|
||||||
|
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" up')
|
||||||
|
|
||||||
|
self.wd.stop()
|
||||||
|
self.wd = None
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.bss0_rule.signal = -8000
|
||||||
|
self.bss1_rule.signal = -8000
|
||||||
|
|
||||||
|
self.wd = IWD(True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
hwsim = Hwsim()
|
||||||
|
|
||||||
|
IWD.copy_to_storage('TestFT.psk')
|
||||||
|
|
||||||
|
cls.bss_hostapd = [ HostapdCLI(config='ft-psk-ccmp-1.conf'),
|
||||||
|
HostapdCLI(config='ft-psk-ccmp-2.conf') ]
|
||||||
|
|
||||||
|
rad0 = hwsim.get_radio('rad0')
|
||||||
|
rad1 = hwsim.get_radio('rad1')
|
||||||
|
|
||||||
|
cls.bss0_rule = hwsim.rules.create()
|
||||||
|
cls.bss0_rule.source = rad0.addresses[0]
|
||||||
|
cls.bss0_rule.bidirectional = True
|
||||||
|
cls.bss0_rule.signal = -8000
|
||||||
|
cls.bss0_rule.enabled = True
|
||||||
|
|
||||||
|
cls.bss1_rule = hwsim.rules.create()
|
||||||
|
cls.bss1_rule.source = rad1.addresses[0]
|
||||||
|
cls.bss1_rule.bidirectional = True
|
||||||
|
cls.bss1_rule.signal = -8000
|
||||||
|
cls.bss1_rule.enabled = True
|
||||||
|
|
||||||
|
cls.bss_hostapd[0].set_address('12:00:00:00:00:01')
|
||||||
|
cls.bss_hostapd[1].set_address('12:00:00:00:00:02')
|
||||||
|
|
||||||
|
HostapdCLI.group_neighbors(*cls.bss_hostapd)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
IWD.clear_storage()
|
||||||
|
cls.bss_hostapd = None
|
||||||
|
cls.bss0_rule.remove()
|
||||||
|
cls.bss1_rule.remove()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main(exit=True)
|
||||||
2
autotests/testBSSBlacklist/TestBlacklist.psk
Normal file
2
autotests/testBSSBlacklist/TestBlacklist.psk
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[Security]
|
||||||
|
Passphrase=secret123
|
||||||
@ -260,12 +260,69 @@ class Test(unittest.TestCase):
|
|||||||
|
|
||||||
self.wd.unregister_psk_agent(psk_agent)
|
self.wd.unregister_psk_agent(psk_agent)
|
||||||
|
|
||||||
|
def test_blacklist_disabled(self):
|
||||||
|
wd = self.wd
|
||||||
|
bss_hostapd = self.bss_hostapd
|
||||||
|
|
||||||
|
rule0 = self.rule0
|
||||||
|
rule1 = self.rule1
|
||||||
|
rule2 = self.rule2
|
||||||
|
|
||||||
|
psk_agent = PSKAgent(["secret123", 'secret123'])
|
||||||
|
wd.register_psk_agent(psk_agent)
|
||||||
|
|
||||||
|
devices = wd.list_devices(1)
|
||||||
|
device = devices[0]
|
||||||
|
|
||||||
|
rule0.drop = True
|
||||||
|
rule0.enabled = True
|
||||||
|
|
||||||
|
device.autoconnect = True
|
||||||
|
|
||||||
|
condition = 'obj.state == DeviceState.connected'
|
||||||
|
wd.wait_for_object_condition(device, condition)
|
||||||
|
|
||||||
|
ordered_network = device.get_ordered_network("TestBlacklist", full_scan=True)
|
||||||
|
|
||||||
|
self.assertEqual(ordered_network.type, NetworkType.psk)
|
||||||
|
|
||||||
|
# The first BSS should fail, and we should connect to the second. This
|
||||||
|
# should not result in a connection blacklist though since its disabled.
|
||||||
|
bss_hostapd[1].wait_for_event('AP-STA-CONNECTED %s' % device.address)
|
||||||
|
|
||||||
|
device.disconnect()
|
||||||
|
|
||||||
|
rule0.drop = False
|
||||||
|
device.autoconnect = True
|
||||||
|
|
||||||
|
# Verify the first BSS wasn't blacklisted.
|
||||||
|
bss_hostapd[0].wait_for_event('AP-STA-CONNECTED %s' % device.address)
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
_, _, name = self.id().split(".")
|
||||||
|
|
||||||
|
# TODO: If we have this pattern elsewhere it might be nice to turn this
|
||||||
|
# into a decorator e.g.
|
||||||
|
#
|
||||||
|
# @config("main.conf.disabled")
|
||||||
|
# @profile("TestBlacklist.psk")
|
||||||
|
# def test_blacklist_disabled(self)
|
||||||
|
# ...
|
||||||
|
#
|
||||||
|
if name == "test_blacklist_disabled":
|
||||||
|
IWD.copy_to_storage("main.conf.disabled", IWD_CONFIG_DIR, "main.conf")
|
||||||
|
IWD.copy_to_storage("TestBlacklist.psk")
|
||||||
|
else:
|
||||||
|
IWD.copy_to_storage("main.conf.default", IWD_CONFIG_DIR, "main.conf")
|
||||||
|
|
||||||
self.wd = IWD(True)
|
self.wd = IWD(True)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
IWD.clear_storage()
|
IWD.clear_storage()
|
||||||
self.wd = None
|
self.wd = None
|
||||||
|
self.rule0.drop = False
|
||||||
|
self.rule1.drop = False
|
||||||
|
self.rule2.drop = False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
|
|||||||
2
autotests/testBSSBlacklist/main.conf.disabled
Normal file
2
autotests/testBSSBlacklist/main.conf.disabled
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
[Blacklist]
|
||||||
|
InitialTimeout=0
|
||||||
98
autotests/testBasicServiceSet/basic_service_set_test.py
Normal file
98
autotests/testBasicServiceSet/basic_service_set_test.py
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
#! /usr/bin/python3
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import sys, os
|
||||||
|
|
||||||
|
sys.path.append('../util')
|
||||||
|
import iwd
|
||||||
|
from iwd import IWD
|
||||||
|
from iwd import PSKAgent
|
||||||
|
from iwd import NetworkType
|
||||||
|
from hwsim import Hwsim
|
||||||
|
from hostapd import HostapdCLI
|
||||||
|
import testutil
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
def test_bss_unregister(self):
|
||||||
|
device = self.wd.list_devices(1)[0]
|
||||||
|
|
||||||
|
ordered_network = device.get_ordered_network('ssidTKIP', full_scan=True)
|
||||||
|
network = ordered_network.network_object
|
||||||
|
|
||||||
|
self.assertEqual(len(network.extended_service_set), 2)
|
||||||
|
|
||||||
|
ends = [parts.split('/')[-1] for parts in network.extended_service_set]
|
||||||
|
|
||||||
|
self.assertIn(self.bss_hostapd[0].bssid.replace(':', ''), ends)
|
||||||
|
self.assertIn(self.bss_hostapd[1].bssid.replace(':', ''), ends)
|
||||||
|
|
||||||
|
self.rule_bss1.enabled = True
|
||||||
|
|
||||||
|
# Even with flushing, the kernel still seems to return the scan
|
||||||
|
# results
|
||||||
|
self.wd.wait(40)
|
||||||
|
ordered_network = device.get_ordered_network('ssidTKIP', full_scan=True)
|
||||||
|
network = ordered_network.network_object
|
||||||
|
|
||||||
|
ends = [parts.split('/')[-1] for parts in network.extended_service_set]
|
||||||
|
|
||||||
|
self.assertIn(self.bss_hostapd[0].bssid.replace(':', ''), ends)
|
||||||
|
self.assertNotIn(self.bss_hostapd[1].bssid.replace(':', ''), ends)
|
||||||
|
|
||||||
|
self.rule_bss0.enabled = True
|
||||||
|
|
||||||
|
self.wd.wait(40)
|
||||||
|
ordered_networks = device.get_ordered_networks('ssidTKIP', full_scan=True)
|
||||||
|
self.assertIsNone(ordered_networks)
|
||||||
|
|
||||||
|
self.rule_bss0.enabled = False
|
||||||
|
|
||||||
|
ordered_networks = device.get_ordered_networks('ssidTKIP', full_scan=True)
|
||||||
|
ends = [parts.split('/')[-1] for parts in network.extended_service_set]
|
||||||
|
|
||||||
|
self.assertIn(self.bss_hostapd[0].bssid.replace(':', ''), ends)
|
||||||
|
self.assertNotIn(self.bss_hostapd[1].bssid.replace(':', ''), ends)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.rule_bss0.enabled = False
|
||||||
|
self.rule_bss1.enabled = False
|
||||||
|
|
||||||
|
self.wd.stop()
|
||||||
|
self.wd.wait(10)
|
||||||
|
self.wd = None
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.wd = IWD(True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
hwsim = Hwsim()
|
||||||
|
|
||||||
|
IWD.copy_to_storage('ssidTKIP.psk')
|
||||||
|
|
||||||
|
cls.bss_hostapd = [ HostapdCLI(config='ssidTKIP-1.conf'),
|
||||||
|
HostapdCLI(config='ssidTKIP-2.conf') ]
|
||||||
|
|
||||||
|
|
||||||
|
rad0 = hwsim.get_radio('rad0')
|
||||||
|
rad1 = hwsim.get_radio('rad1')
|
||||||
|
|
||||||
|
cls.rule_bss0 = hwsim.rules.create()
|
||||||
|
cls.rule_bss0.source = rad0.addresses[0]
|
||||||
|
cls.rule_bss0.bidirectional = True
|
||||||
|
cls.rule_bss0.drop = True
|
||||||
|
|
||||||
|
cls.rule_bss1 = hwsim.rules.create()
|
||||||
|
cls.rule_bss1.source = rad1.addresses[0]
|
||||||
|
cls.rule_bss1.bidirectional = True
|
||||||
|
cls.rule_bss1.drop = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
IWD.clear_storage()
|
||||||
|
cls.bss_hostapd = None
|
||||||
|
cls.rule_bss0.remove()
|
||||||
|
cls.rule_bss1.remove()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main(exit=True)
|
||||||
8
autotests/testBasicServiceSet/hw.conf
Normal file
8
autotests/testBasicServiceSet/hw.conf
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
[SETUP]
|
||||||
|
num_radios=3
|
||||||
|
hwsim_medium=yes
|
||||||
|
start_iwd=no
|
||||||
|
|
||||||
|
[HOSTAPD]
|
||||||
|
rad0=ssidTKIP-1.conf
|
||||||
|
rad1=ssidTKIP-2.conf
|
||||||
7
autotests/testBasicServiceSet/ssidTKIP-1.conf
Normal file
7
autotests/testBasicServiceSet/ssidTKIP-1.conf
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
hw_mode=g
|
||||||
|
channel=1
|
||||||
|
ssid=ssidTKIP
|
||||||
|
|
||||||
|
wpa=1
|
||||||
|
wpa_pairwise=TKIP
|
||||||
|
wpa_passphrase=secret123
|
||||||
7
autotests/testBasicServiceSet/ssidTKIP-2.conf
Normal file
7
autotests/testBasicServiceSet/ssidTKIP-2.conf
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
hw_mode=g
|
||||||
|
channel=2
|
||||||
|
ssid=ssidTKIP
|
||||||
|
|
||||||
|
wpa=1
|
||||||
|
wpa_pairwise=TKIP
|
||||||
|
wpa_passphrase=secret123
|
||||||
5
autotests/testBasicServiceSet/ssidTKIP.psk
Normal file
5
autotests/testBasicServiceSet/ssidTKIP.psk
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[Security]
|
||||||
|
Passphrase=secret123
|
||||||
|
|
||||||
|
[Settings]
|
||||||
|
AutoConnect=False
|
||||||
@ -11,7 +11,7 @@ from iwd import IWD
|
|||||||
|
|
||||||
class Test8021xNetwork(unittest.TestCase):
|
class Test8021xNetwork(unittest.TestCase):
|
||||||
'''
|
'''
|
||||||
The bellow test cases excesise the following connection scenarios:
|
The below test cases excesise the following connection scenarios:
|
||||||
|
|
||||||
Network config is
|
Network config is
|
||||||
present at start time: Connect: AutoConnect: Result:
|
present at start time: Connect: AutoConnect: Result:
|
||||||
|
|||||||
@ -11,7 +11,7 @@ from iwd import IWD
|
|||||||
|
|
||||||
class TestOpenNetwork(unittest.TestCase):
|
class TestOpenNetwork(unittest.TestCase):
|
||||||
'''
|
'''
|
||||||
The bellow test cases excesise the following connection scenarios:
|
The below test cases excesise the following connection scenarios:
|
||||||
|
|
||||||
Network config is
|
Network config is
|
||||||
present at start time: Connect: AutoConnect: Result:
|
present at start time: Connect: AutoConnect: Result:
|
||||||
|
|||||||
@ -11,7 +11,7 @@ from iwd import IWD
|
|||||||
|
|
||||||
class TestWpaNetwork(unittest.TestCase):
|
class TestWpaNetwork(unittest.TestCase):
|
||||||
'''
|
'''
|
||||||
The bellow test cases exercise the following connection scenarios:
|
The below test cases exercise the following connection scenarios:
|
||||||
|
|
||||||
Network config is
|
Network config is
|
||||||
present at start time: Connect: AutoConnect: Result:
|
present at start time: Connect: AutoConnect: Result:
|
||||||
|
|||||||
@ -38,20 +38,18 @@ class Test(unittest.TestCase):
|
|||||||
|
|
||||||
def test_iwd_as_enrollee_scan_after(self):
|
def test_iwd_as_enrollee_scan_after(self):
|
||||||
self.wpas.disconnect()
|
self.wpas.disconnect()
|
||||||
|
self.device.autoconnect = True
|
||||||
uri = self.device.dpp_start_enrollee()
|
uri = self.device.dpp_start_enrollee()
|
||||||
|
|
||||||
self.wpas.dpp_configurator_create(uri)
|
self.wpas.dpp_configurator_create(uri)
|
||||||
self.wpas.dpp_configurator_start('ssidCCMP', 'secret123')
|
self.wpas.dpp_configurator_start('ssidCCMP', 'secret123')
|
||||||
|
|
||||||
self.hapd.reload()
|
|
||||||
|
|
||||||
with self.assertRaises(Exception):
|
with self.assertRaises(Exception):
|
||||||
self.device.get_ordered_network('ssidCCMP', scan_if_needed=False)
|
self.device.get_ordered_network('ssidCCMP', scan_if_needed=False)
|
||||||
|
|
||||||
|
self.hapd.reload()
|
||||||
self.hapd.wait_for_event('AP-ENABLED')
|
self.hapd.wait_for_event('AP-ENABLED')
|
||||||
|
|
||||||
self.device.autoconnect = True
|
|
||||||
|
|
||||||
condition = 'obj.state == DeviceState.connected'
|
condition = 'obj.state == DeviceState.connected'
|
||||||
self.wd.wait_for_object_condition(self.device, condition)
|
self.wd.wait_for_object_condition(self.device, condition)
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import unittest
|
|||||||
import sys
|
import sys
|
||||||
|
|
||||||
sys.path.append('../util')
|
sys.path.append('../util')
|
||||||
from iwd import IWD, SharedCodeAgent
|
from iwd import IWD, SharedCodeAgent, DeviceState
|
||||||
from iwd import DeviceProvisioning
|
from iwd import DeviceProvisioning
|
||||||
from wpas import Wpas
|
from wpas import Wpas
|
||||||
from hostapd import HostapdCLI
|
from hostapd import HostapdCLI
|
||||||
@ -160,10 +160,8 @@ class Test(unittest.TestCase):
|
|||||||
|
|
||||||
def test_pkex_iwd_to_iwd(self):
|
def test_pkex_iwd_to_iwd(self):
|
||||||
self.start_iwd_pkex_configurator(self.device[0])
|
self.start_iwd_pkex_configurator(self.device[0])
|
||||||
|
|
||||||
self.device[1].dpp_pkex_enroll('secret123', identifier="test")
|
|
||||||
|
|
||||||
self.device[1].autoconnect = True
|
self.device[1].autoconnect = True
|
||||||
|
self.device[1].dpp_pkex_enroll('secret123', identifier="test")
|
||||||
|
|
||||||
condition = 'obj.state == DeviceState.connected'
|
condition = 'obj.state == DeviceState.connected'
|
||||||
self.wd.wait_for_object_condition(self.device[1], condition)
|
self.wd.wait_for_object_condition(self.device[1], condition)
|
||||||
@ -176,10 +174,8 @@ class Test(unittest.TestCase):
|
|||||||
|
|
||||||
def test_pkex_configurator_with_agent(self):
|
def test_pkex_configurator_with_agent(self):
|
||||||
self.start_iwd_pkex_configurator(self.device[0], agent=True)
|
self.start_iwd_pkex_configurator(self.device[0], agent=True)
|
||||||
|
|
||||||
self.device[1].dpp_pkex_enroll('secret123', identifier="test")
|
|
||||||
|
|
||||||
self.device[1].autoconnect = True
|
self.device[1].autoconnect = True
|
||||||
|
self.device[1].dpp_pkex_enroll('secret123', identifier="test")
|
||||||
|
|
||||||
condition = 'obj.state == DeviceState.connected'
|
condition = 'obj.state == DeviceState.connected'
|
||||||
self.wd.wait_for_object_condition(self.device[1], condition)
|
self.wd.wait_for_object_condition(self.device[1], condition)
|
||||||
@ -198,8 +194,8 @@ class Test(unittest.TestCase):
|
|||||||
|
|
||||||
self.start_iwd_pkex_configurator(self.device[0])
|
self.start_iwd_pkex_configurator(self.device[0])
|
||||||
|
|
||||||
self.device[1].dpp_pkex_enroll('secret123', identifier="test")
|
|
||||||
self.device[1].autoconnect = False
|
self.device[1].autoconnect = False
|
||||||
|
self.device[1].dpp_pkex_enroll('secret123', identifier="test")
|
||||||
|
|
||||||
condition = 'obj.state == DeviceState.connected'
|
condition = 'obj.state == DeviceState.connected'
|
||||||
self.wd.wait_for_object_condition(self.device[1], condition)
|
self.wd.wait_for_object_condition(self.device[1], condition)
|
||||||
@ -210,6 +206,24 @@ class Test(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertIn("SendHostname=true", settings)
|
self.assertIn("SendHostname=true", settings)
|
||||||
|
|
||||||
|
def test_existing_incorrect_profile(self):
|
||||||
|
self.hapd.reload()
|
||||||
|
self.hapd.wait_for_event('AP-ENABLED')
|
||||||
|
IWD.copy_to_storage("existingProfile.psk", "/tmp/ns0/", "ssidCCMP.psk")
|
||||||
|
|
||||||
|
# Start connecting
|
||||||
|
self.device[1].autoconnect = True
|
||||||
|
self.wd.wait_for_object_condition(self.device[1], 'obj.state == DeviceState.connecting')
|
||||||
|
|
||||||
|
# We should be able to start DPP despite the connecting state
|
||||||
|
self.device[1].dpp_pkex_enroll('secret123', identifier="test")
|
||||||
|
|
||||||
|
self.start_iwd_pkex_configurator(self.device[0])
|
||||||
|
self.assertEqual(self.device[1].state, DeviceState.disconnected)
|
||||||
|
|
||||||
|
condition = 'obj.state == DeviceState.connected'
|
||||||
|
self.wd.wait_for_object_condition(self.device[1], condition)
|
||||||
|
|
||||||
def test_existing_hidden_network(self):
|
def test_existing_hidden_network(self):
|
||||||
self.hapd_hidden.reload()
|
self.hapd_hidden.reload()
|
||||||
self.hapd_hidden.wait_for_event('AP-ENABLED')
|
self.hapd_hidden.wait_for_event('AP-ENABLED')
|
||||||
@ -222,8 +236,9 @@ class Test(unittest.TestCase):
|
|||||||
|
|
||||||
self.start_iwd_pkex_configurator(self.device[0], profile='ssidHidden.psk')
|
self.start_iwd_pkex_configurator(self.device[0], profile='ssidHidden.psk')
|
||||||
|
|
||||||
self.device[1].dpp_pkex_enroll('secret123', identifier="test")
|
|
||||||
self.device[1].autoconnect = False
|
self.device[1].autoconnect = False
|
||||||
|
self.device[1].dpp_pkex_enroll('secret123', identifier="test")
|
||||||
|
|
||||||
|
|
||||||
condition = 'obj.state == DeviceState.connected'
|
condition = 'obj.state == DeviceState.connected'
|
||||||
self.wd.wait_for_object_condition(self.device[1], condition)
|
self.wd.wait_for_object_condition(self.device[1], condition)
|
||||||
@ -239,8 +254,8 @@ class Test(unittest.TestCase):
|
|||||||
self.hapd_hidden.wait_for_event('AP-ENABLED')
|
self.hapd_hidden.wait_for_event('AP-ENABLED')
|
||||||
self.start_iwd_pkex_configurator(self.device[0], profile='ssidHidden.psk')
|
self.start_iwd_pkex_configurator(self.device[0], profile='ssidHidden.psk')
|
||||||
|
|
||||||
self.device[1].dpp_pkex_enroll('secret123', identifier="test")
|
|
||||||
self.device[1].autoconnect = False
|
self.device[1].autoconnect = False
|
||||||
|
self.device[1].dpp_pkex_enroll('secret123', identifier="test")
|
||||||
|
|
||||||
condition = 'obj.state == DeviceState.connected'
|
condition = 'obj.state == DeviceState.connected'
|
||||||
self.wd.wait_for_object_condition(self.device[1], condition)
|
self.wd.wait_for_object_condition(self.device[1], condition)
|
||||||
|
|||||||
107
autotests/testDPP/state_change_test.py
Normal file
107
autotests/testDPP/state_change_test.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.append('../util')
|
||||||
|
from iwd import IWD, SharedCodeAgent, DeviceState
|
||||||
|
from iwd import DeviceProvisioning
|
||||||
|
from wpas import Wpas
|
||||||
|
from hostapd import HostapdCLI
|
||||||
|
from hwsim import Hwsim
|
||||||
|
from config import ctx
|
||||||
|
from time import time
|
||||||
|
import os
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
def auto_connect(self):
|
||||||
|
IWD.copy_to_storage('ssidCCMP.psk')
|
||||||
|
self.device.autoconnect = True
|
||||||
|
|
||||||
|
condition = 'obj.state == DeviceState.connected'
|
||||||
|
self.wd.wait_for_object_condition(self.device, condition)
|
||||||
|
|
||||||
|
def test_configurator_stops_on_disconnect(self):
|
||||||
|
self.auto_connect()
|
||||||
|
|
||||||
|
self.device.dpp_start_configurator()
|
||||||
|
|
||||||
|
self.device.disconnect()
|
||||||
|
|
||||||
|
condition = 'obj.state == DeviceState.disconnected'
|
||||||
|
self.wd.wait_for_object_condition(self.device, condition)
|
||||||
|
|
||||||
|
self.assertEqual(self.device._device_provisioning.started, False)
|
||||||
|
|
||||||
|
def test_enrollee_stops_on_connect(self):
|
||||||
|
# Scan to get a list of networks
|
||||||
|
self.device.scan()
|
||||||
|
self.wd.wait_for_object_condition(self.device, 'obj.scanning == True')
|
||||||
|
self.wd.wait_for_object_condition(self.device, 'obj.scanning == False')
|
||||||
|
|
||||||
|
self.device.dpp_start_enrollee()
|
||||||
|
|
||||||
|
network = self.device.get_ordered_network("ssidCCMP")
|
||||||
|
network.network_object.connect()
|
||||||
|
|
||||||
|
condition = 'obj.state == DeviceState.connected'
|
||||||
|
self.wd.wait_for_object_condition(self.device, condition)
|
||||||
|
|
||||||
|
self.assertEqual(self.device._device_provisioning.started, False)
|
||||||
|
|
||||||
|
def test_enrollee_disconnects_automatically(self):
|
||||||
|
self.auto_connect()
|
||||||
|
|
||||||
|
self.device.dpp_start_enrollee()
|
||||||
|
|
||||||
|
condition = 'obj.state == DeviceState.disconnected'
|
||||||
|
self.wd.wait_for_object_condition(self.device, condition)
|
||||||
|
|
||||||
|
def test_enrollee_autoconnect_stays_on(self):
|
||||||
|
# Put in an autoconnecting state, no saved profile though
|
||||||
|
self.device.autoconnect = True
|
||||||
|
|
||||||
|
self.device.dpp_start_enrollee()
|
||||||
|
|
||||||
|
# DPP should set autoconnect false, but then re-enable after it stops
|
||||||
|
self.wd.wait_for_object_condition(self.device, "obj.autoconnect == False")
|
||||||
|
self.wd.wait_for_object_condition(self.device._device_provisioning, "obj.started == True")
|
||||||
|
|
||||||
|
# Stop DPP
|
||||||
|
self.device.dpp_stop()
|
||||||
|
self.wd.wait_for_object_condition(self.device, "obj.autoconnect == True")
|
||||||
|
|
||||||
|
def test_enrollee_autoconnect_stays_off(self):
|
||||||
|
# Autoconnect should be off by default
|
||||||
|
|
||||||
|
self.device.dpp_start_enrollee()
|
||||||
|
|
||||||
|
# DPP should set autoconnect false, but stay off after it stops
|
||||||
|
self.wd.wait_for_object_condition(self.device, "obj.autoconnect == False")
|
||||||
|
self.wd.wait_for_object_condition(self.device._device_provisioning, "obj.started == True")
|
||||||
|
|
||||||
|
# Stop DPP
|
||||||
|
self.device.dpp_stop()
|
||||||
|
self.wd.wait_for_object_condition(self.device, "obj.autoconnect == False")
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.wd = IWD(True)
|
||||||
|
self.device = self.wd.list_devices(1)[0]
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.wd.stop()
|
||||||
|
self.wd = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
hapd = HostapdCLI(config="hostapd.conf")
|
||||||
|
hapd.reload()
|
||||||
|
|
||||||
|
hapd.wait_for_event("AP-ENABLED")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main(exit=True)
|
||||||
@ -104,7 +104,7 @@ class Test(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertTrue(self.profile_is_encrypted('ssidCCMP.psk'))
|
self.assertTrue(self.profile_is_encrypted('ssidCCMP.psk'))
|
||||||
|
|
||||||
# Tests that a profile that doesn't decrypt wont become a known network
|
# Tests that a profile that doesn't decrypt won't become a known network
|
||||||
def test_decryption_failure(self):
|
def test_decryption_failure(self):
|
||||||
bad_config = \
|
bad_config = \
|
||||||
'''
|
'''
|
||||||
|
|||||||
@ -1,2 +1,5 @@
|
|||||||
[Security]
|
[Security]
|
||||||
Passphrase=secret123
|
Passphrase=secret123
|
||||||
|
|
||||||
|
[General]
|
||||||
|
AutoConnect=false
|
||||||
|
|||||||
@ -3,7 +3,11 @@ import sys
|
|||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
from scapy.layers.dot11 import *
|
from scapy.layers.dot11 import *
|
||||||
from scapy.arch import str2mac, get_if_raw_hwaddr
|
from scapy.arch import str2mac
|
||||||
|
try:
|
||||||
|
from scapy.arch import get_if_raw_hwaddr
|
||||||
|
except:
|
||||||
|
from scapy.arch.unix import get_if_raw_hwaddr
|
||||||
from time import time, sleep
|
from time import time, sleep
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
|
|||||||
@ -12,7 +12,7 @@ from hostapd import HostapdCLI
|
|||||||
|
|
||||||
class TestWpaNetwork(unittest.TestCase):
|
class TestWpaNetwork(unittest.TestCase):
|
||||||
'''
|
'''
|
||||||
The bellow test cases excesise the following connection scenarios:
|
The below test cases excesise the following connection scenarios:
|
||||||
|
|
||||||
Network config is
|
Network config is
|
||||||
present at start time: Connect: AutoConnect: Result:
|
present at start time: Connect: AutoConnect: Result:
|
||||||
|
|||||||
@ -12,7 +12,7 @@ from hostapd import HostapdCLI
|
|||||||
|
|
||||||
class TestOpenNetwork(unittest.TestCase):
|
class TestOpenNetwork(unittest.TestCase):
|
||||||
'''
|
'''
|
||||||
The bellow test cases excesise the following connection scenarios:
|
The below test cases excesise the following connection scenarios:
|
||||||
|
|
||||||
Network config is
|
Network config is
|
||||||
present at start time: Connect: AutoConnect: Result:
|
present at start time: Connect: AutoConnect: Result:
|
||||||
|
|||||||
@ -12,7 +12,7 @@ from hostapd import HostapdCLI
|
|||||||
|
|
||||||
class TestWpaNetwork(unittest.TestCase):
|
class TestWpaNetwork(unittest.TestCase):
|
||||||
'''
|
'''
|
||||||
The bellow test cases excesise the following connection scenarios:
|
The below test cases excesise the following connection scenarios:
|
||||||
|
|
||||||
Network config is
|
Network config is
|
||||||
present at start time: Connect: AutoConnect: Result:
|
present at start time: Connect: AutoConnect: Result:
|
||||||
|
|||||||
@ -11,7 +11,7 @@ from iwd import NetworkType
|
|||||||
|
|
||||||
class TestMFP(unittest.TestCase):
|
class TestMFP(unittest.TestCase):
|
||||||
'''
|
'''
|
||||||
The bellow test cases excesise the following MFP option setting scenarios:
|
The below test cases excesise the following MFP option setting scenarios:
|
||||||
|
|
||||||
IWD_MFP: AP_MFP: Result:
|
IWD_MFP: AP_MFP: Result:
|
||||||
0 0 No MFP, connection succeeds
|
0 0 No MFP, connection succeeds
|
||||||
|
|||||||
@ -137,7 +137,7 @@ class Test(unittest.TestCase):
|
|||||||
# since (T2 - T1) / 2 is shorter than 60s. It is now about 10s since the last
|
# since (T2 - T1) / 2 is shorter than 60s. It is now about 10s since the last
|
||||||
# renewal or 5s before the next DHCPREQUEST frame that is going to be lost. We'll
|
# renewal or 5s before the next DHCPREQUEST frame that is going to be lost. We'll
|
||||||
# wait T1 seconds, so until about 10s after the failed attempt, we'll check that
|
# wait T1 seconds, so until about 10s after the failed attempt, we'll check that
|
||||||
# there was no renewal by that time, just in case, and we'll reenable frame delivery.
|
# there was no renewal by that time, just in case, and we'll re-enable frame delivery.
|
||||||
# We'll then wait another 60s and we should see the lease has been successfully
|
# We'll then wait another 60s and we should see the lease has been successfully
|
||||||
# renewed some 10 seconds earlier on the 1st DHCPREQUEST retransmission.
|
# renewed some 10 seconds earlier on the 1st DHCPREQUEST retransmission.
|
||||||
#
|
#
|
||||||
|
|||||||
@ -91,16 +91,11 @@ class Test(unittest.TestCase):
|
|||||||
# using the same static config. The new client's ACD client should
|
# using the same static config. The new client's ACD client should
|
||||||
# detect an IP conflict and not allow the device to reach the
|
# detect an IP conflict and not allow the device to reach the
|
||||||
# "connected" state although the DBus .Connect call will succeed.
|
# "connected" state although the DBus .Connect call will succeed.
|
||||||
ordered_network.network_object.connect()
|
with self.assertRaises(iwd.FailedEx):
|
||||||
self.assertEqual(dev2.state, iwd.DeviceState.connecting)
|
ordered_network.network_object.connect(timeout=500)
|
||||||
try:
|
|
||||||
# We should either stay in "connecting" indefinitely or move to
|
condition = 'obj.state == DeviceState.disconnected'
|
||||||
# "disconnecting"
|
iwd_ns0_1.wait_for_object_condition(dev2, condition, max_wait=21)
|
||||||
condition = 'obj.state != DeviceState.connecting'
|
|
||||||
iwd_ns0_1.wait_for_object_condition(dev2, condition, max_wait=21)
|
|
||||||
self.assertEqual(dev2.state, iwd.DeviceState.disconnecting)
|
|
||||||
except TimeoutError:
|
|
||||||
dev2.disconnect()
|
|
||||||
|
|
||||||
iwd_ns0_1.unregister_psk_agent(psk_agent_ns0_1)
|
iwd_ns0_1.unregister_psk_agent(psk_agent_ns0_1)
|
||||||
del dev2
|
del dev2
|
||||||
|
|||||||
@ -8,6 +8,8 @@ from iwd import PSKAgent
|
|||||||
from iwd import NetworkType
|
from iwd import NetworkType
|
||||||
|
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
|
def connect_failure(self, ex):
|
||||||
|
self.failure_triggered = True
|
||||||
|
|
||||||
def test_netconfig_timeout(self):
|
def test_netconfig_timeout(self):
|
||||||
IWD.copy_to_storage('autoconnect.psk', name='ap-ns1.psk')
|
IWD.copy_to_storage('autoconnect.psk', name='ap-ns1.psk')
|
||||||
@ -27,23 +29,34 @@ class Test(unittest.TestCase):
|
|||||||
condition = 'not obj.connected'
|
condition = 'not obj.connected'
|
||||||
wd.wait_for_object_condition(ordered_network.network_object, condition)
|
wd.wait_for_object_condition(ordered_network.network_object, condition)
|
||||||
|
|
||||||
ordered_network.network_object.connect()
|
self.failure_triggered = False
|
||||||
|
|
||||||
condition = 'obj.state == DeviceState.connecting'
|
# Set our error handler here so we can check if it fails
|
||||||
|
ordered_network.network_object.connect(
|
||||||
|
wait=False,
|
||||||
|
timeout=1000,
|
||||||
|
error_handler=self.connect_failure
|
||||||
|
)
|
||||||
|
|
||||||
|
# IWD should attempt to try both BSS's with both failing netconfig.
|
||||||
|
# Then the autoconnect list should be exhausted, and IWD should
|
||||||
|
# transition to a disconnected state, then proceed to full autoconnect.
|
||||||
|
device.wait_for_event("netconfig-failed", timeout=1000)
|
||||||
|
device.wait_for_event("netconfig-failed", timeout=1000)
|
||||||
|
device.wait_for_event("disconnected")
|
||||||
|
|
||||||
|
device.wait_for_event("autoconnect_full")
|
||||||
|
|
||||||
|
# The connect call should have failed
|
||||||
|
self.assertTrue(self.failure_triggered)
|
||||||
|
|
||||||
|
condition = "obj.scanning"
|
||||||
|
wd.wait_for_object_condition(device, condition)
|
||||||
|
condition = "not obj.scanning"
|
||||||
wd.wait_for_object_condition(device, condition)
|
wd.wait_for_object_condition(device, condition)
|
||||||
|
|
||||||
device.wait_for_event("connecting (netconfig)")
|
# IWD should attempt to connect, but it will of course fail again.
|
||||||
|
device.wait_for_event("netconfig-failed", timeout=1000)
|
||||||
# Netconfig should fail, and IWD should disconnect
|
|
||||||
from_condition = 'obj.state == DeviceState.connecting'
|
|
||||||
to_condition = 'obj.state == DeviceState.disconnecting'
|
|
||||||
wd.wait_for_object_change(device, from_condition, to_condition, max_wait=60)
|
|
||||||
|
|
||||||
# Autoconnect should then try again
|
|
||||||
condition = 'obj.state == DeviceState.connecting'
|
|
||||||
wd.wait_for_object_condition(device, condition)
|
|
||||||
|
|
||||||
device.wait_for_event("connecting (netconfig)")
|
|
||||||
|
|
||||||
device.disconnect()
|
device.disconnect()
|
||||||
condition = 'obj.state == DeviceState.disconnected'
|
condition = 'obj.state == DeviceState.disconnected'
|
||||||
|
|||||||
@ -19,7 +19,7 @@ class Test(unittest.TestCase):
|
|||||||
|
|
||||||
device = wd.list_devices(1)[0]
|
device = wd.list_devices(1)[0]
|
||||||
device.get_ordered_network('TestFT', full_scan=True)
|
device.get_ordered_network('TestFT', full_scan=True)
|
||||||
device.connect_bssid(self.bss_hostapd[1].bssid)
|
device.connect_bssid(self.bss_hostapd[1].bssid, wait=False)
|
||||||
|
|
||||||
self.bss_hostapd[1].wait_for_event(f'AP-STA-CONNECTED {device.address}')
|
self.bss_hostapd[1].wait_for_event(f'AP-STA-CONNECTED {device.address}')
|
||||||
device.wait_for_event("connecting (netconfig)")
|
device.wait_for_event("connecting (netconfig)")
|
||||||
|
|||||||
114
autotests/testPMKSA-SAE/connection_test.py
Normal file
114
autotests/testPMKSA-SAE/connection_test.py
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.append('../util')
|
||||||
|
from iwd import IWD
|
||||||
|
from iwd import PSKAgent
|
||||||
|
from iwd import NetworkType
|
||||||
|
from hostapd import HostapdCLI
|
||||||
|
import testutil
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
|
||||||
|
def validate_connection(self, wd, ssid, hostapd, expected_group):
|
||||||
|
psk_agent = PSKAgent("secret123")
|
||||||
|
wd.register_psk_agent(psk_agent)
|
||||||
|
|
||||||
|
devices = wd.list_devices(1)
|
||||||
|
self.assertIsNotNone(devices)
|
||||||
|
device = devices[0]
|
||||||
|
|
||||||
|
device.disconnect()
|
||||||
|
|
||||||
|
network = device.get_ordered_network(ssid, full_scan=True)
|
||||||
|
|
||||||
|
self.assertEqual(network.type, NetworkType.psk)
|
||||||
|
|
||||||
|
network.network_object.connect()
|
||||||
|
|
||||||
|
condition = 'obj.state == DeviceState.connected'
|
||||||
|
wd.wait_for_object_condition(device, condition)
|
||||||
|
|
||||||
|
wd.wait(2)
|
||||||
|
|
||||||
|
testutil.test_iface_operstate(intf=device.name)
|
||||||
|
testutil.test_ifaces_connected(if0=device.name, if1=hostapd.ifname)
|
||||||
|
|
||||||
|
# Initial connection PMKSA should not be used. So we should see the
|
||||||
|
# SAE group set.
|
||||||
|
sta_status = hostapd.sta_status(device.address)
|
||||||
|
self.assertEqual(int(sta_status["sae_group"]), expected_group)
|
||||||
|
|
||||||
|
device.disconnect()
|
||||||
|
|
||||||
|
condition = 'not obj.connected'
|
||||||
|
wd.wait_for_object_condition(network.network_object, condition)
|
||||||
|
|
||||||
|
wd.unregister_psk_agent(psk_agent)
|
||||||
|
|
||||||
|
network.network_object.connect(wait=False)
|
||||||
|
|
||||||
|
condition = 'obj.state == DeviceState.connected'
|
||||||
|
wd.wait_for_object_condition(device, condition)
|
||||||
|
|
||||||
|
wd.wait(2)
|
||||||
|
|
||||||
|
testutil.test_iface_operstate(intf=device.name)
|
||||||
|
testutil.test_ifaces_connected(if0=device.name, if1=hostapd.ifname)
|
||||||
|
|
||||||
|
# Having connected once prior we should have a PMKSA and SAE should not
|
||||||
|
# have been used.
|
||||||
|
sta_status = hostapd.sta_status(device.address)
|
||||||
|
self.assertNotIn("sae_group", sta_status.keys())
|
||||||
|
|
||||||
|
device.disconnect()
|
||||||
|
|
||||||
|
condition = 'not obj.connected'
|
||||||
|
wd.wait_for_object_condition(network.network_object, condition)
|
||||||
|
|
||||||
|
hostapd.pmksa_flush()
|
||||||
|
|
||||||
|
wd.wait(5)
|
||||||
|
|
||||||
|
network.network_object.connect()
|
||||||
|
|
||||||
|
device.wait_for_event("pmksa-invalid-pmkid")
|
||||||
|
|
||||||
|
condition = 'obj.state == DeviceState.connected'
|
||||||
|
wd.wait_for_object_condition(device, condition)
|
||||||
|
|
||||||
|
wd.wait(2)
|
||||||
|
|
||||||
|
testutil.test_iface_operstate(intf=device.name)
|
||||||
|
testutil.test_ifaces_connected(if0=device.name, if1=hostapd.ifname)
|
||||||
|
|
||||||
|
# Manually flushing the PMKSA from the AP then reconnecting we should
|
||||||
|
# have failed (INVALID_PMKID) then retried the same BSS with SAE, not
|
||||||
|
# PMKSA.
|
||||||
|
sta_status = hostapd.sta_status(device.address)
|
||||||
|
self.assertEqual(int(sta_status["sae_group"]), expected_group)
|
||||||
|
|
||||||
|
def test_pmksa_sae(self):
|
||||||
|
self.hostapd.wait_for_event("AP-ENABLED")
|
||||||
|
self.validate_connection(self.wd, "ssidSAE", self.hostapd, 19)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.hostapd.default()
|
||||||
|
self.wd = IWD(True)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.wd.clear_storage()
|
||||||
|
self.wd = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
cls.hostapd = HostapdCLI(config='ssidSAE.conf')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main(exit=True)
|
||||||
7
autotests/testPMKSA-SAE/hw.conf
Normal file
7
autotests/testPMKSA-SAE/hw.conf
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[SETUP]
|
||||||
|
num_radios=2
|
||||||
|
start_iwd=0
|
||||||
|
hwsim_medium=yes
|
||||||
|
|
||||||
|
[HOSTAPD]
|
||||||
|
rad0=ssidSAE.conf
|
||||||
@ -1,6 +1,6 @@
|
|||||||
hw_mode=g
|
hw_mode=g
|
||||||
channel=1
|
channel=1
|
||||||
ssid=ssidSAE-default-group
|
ssid=ssidSAE
|
||||||
|
|
||||||
wpa=2
|
wpa=2
|
||||||
wpa_key_mgmt=SAE
|
wpa_key_mgmt=SAE
|
||||||
@ -9,4 +9,4 @@ sae_password=secret123
|
|||||||
sae_groups=19
|
sae_groups=19
|
||||||
ieee80211w=2
|
ieee80211w=2
|
||||||
sae_pwe=0
|
sae_pwe=0
|
||||||
vendor_elements=dd0cf4f5e8050500000000000000
|
rsn_preauth=1
|
||||||
114
autotests/testPSK-roam/chan_switch_test.py
Normal file
114
autotests/testPSK-roam/chan_switch_test.py
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#! /usr/bin/python3
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import sys, os
|
||||||
|
|
||||||
|
sys.path.append('../util')
|
||||||
|
from iwd import IWD
|
||||||
|
from iwd import NetworkType
|
||||||
|
from hostapd import HostapdCLI
|
||||||
|
from packaging import version
|
||||||
|
from subprocess import run
|
||||||
|
import re
|
||||||
|
import testutil
|
||||||
|
|
||||||
|
#
|
||||||
|
# The CSA handling was added in kernel 6.8, so for any earlier kernel this test
|
||||||
|
# won't pass.
|
||||||
|
#
|
||||||
|
def kernel_is_newer(min_version="6.8"):
|
||||||
|
proc = run(["uname", "-r"], capture_output=True)
|
||||||
|
|
||||||
|
version_str = proc.stdout.decode("utf-8")
|
||||||
|
match = re.match(r"(\d+\.\d+)", version_str)
|
||||||
|
if not match:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return version.parse(match.group(1)) >= version.parse(min_version)
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
def test_channel_switch_during_roam(self):
|
||||||
|
wd = self.wd
|
||||||
|
|
||||||
|
device = wd.list_devices(1)[0]
|
||||||
|
|
||||||
|
ordered_network = device.get_ordered_network('TestFT', full_scan=True)
|
||||||
|
|
||||||
|
self.assertEqual(ordered_network.type, NetworkType.psk)
|
||||||
|
|
||||||
|
condition = 'not obj.connected'
|
||||||
|
wd.wait_for_object_condition(ordered_network.network_object, condition)
|
||||||
|
|
||||||
|
self.assertFalse(self.bss_hostapd[0].list_sta())
|
||||||
|
self.assertFalse(self.bss_hostapd[1].list_sta())
|
||||||
|
|
||||||
|
device.connect_bssid(self.bss_hostapd[0].bssid)
|
||||||
|
|
||||||
|
condition = 'obj.state == DeviceState.connected'
|
||||||
|
wd.wait_for_object_condition(device, condition)
|
||||||
|
|
||||||
|
self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED %s' % device.address)
|
||||||
|
|
||||||
|
testutil.test_iface_operstate(device.name)
|
||||||
|
testutil.test_ifaces_connected(self.bss_hostapd[0].ifname, device.name)
|
||||||
|
self.assertRaises(Exception, testutil.test_ifaces_connected,
|
||||||
|
(self.bss_hostapd[1].ifname, device.name, True, True))
|
||||||
|
|
||||||
|
# Start a channel switch and wait for it to begin
|
||||||
|
self.bss_hostapd[1].chan_switch(6, wait=False)
|
||||||
|
self.bss_hostapd[1].wait_for_event("CTRL-EVENT-STARTED-CHANNEL-SWITCH")
|
||||||
|
# Initiate a roam immediately which should get rejected by the kernel
|
||||||
|
device.roam(self.bss_hostapd[1].bssid)
|
||||||
|
|
||||||
|
# IWD should authenticate, then proceed to association
|
||||||
|
device.wait_for_event("ft-authenticating")
|
||||||
|
device.wait_for_event("ft-roaming")
|
||||||
|
|
||||||
|
# The kernel should reject the association, which should trigger a
|
||||||
|
# disconnect
|
||||||
|
condition = 'obj.state == DeviceState.disconnected'
|
||||||
|
wd.wait_for_object_condition(device, condition)
|
||||||
|
|
||||||
|
condition = 'obj.state == DeviceState.connected'
|
||||||
|
wd.wait_for_object_condition(device, condition)
|
||||||
|
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" down')
|
||||||
|
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" down')
|
||||||
|
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" up')
|
||||||
|
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" up')
|
||||||
|
|
||||||
|
for hapd in self.bss_hostapd:
|
||||||
|
hapd.default()
|
||||||
|
|
||||||
|
self.wd.stop()
|
||||||
|
self.wd = None
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.wd = IWD(True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
if not kernel_is_newer():
|
||||||
|
raise unittest.SkipTest()
|
||||||
|
|
||||||
|
IWD.copy_to_storage('TestFT.psk')
|
||||||
|
|
||||||
|
cls.bss_hostapd = [ HostapdCLI(config='ft-psk-ccmp-1.conf'),
|
||||||
|
HostapdCLI(config='ft-psk-ccmp-2.conf'),
|
||||||
|
HostapdCLI(config='ft-psk-ccmp-3.conf') ]
|
||||||
|
|
||||||
|
unused = HostapdCLI(config='ft-psk-ccmp-3.conf')
|
||||||
|
unused.disable()
|
||||||
|
|
||||||
|
cls.bss_hostapd[0].set_address('12:00:00:00:00:01')
|
||||||
|
cls.bss_hostapd[1].set_address('12:00:00:00:00:02')
|
||||||
|
cls.bss_hostapd[2].set_address('12:00:00:00:00:03')
|
||||||
|
|
||||||
|
HostapdCLI.group_neighbors(*cls.bss_hostapd)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
IWD.clear_storage()
|
||||||
|
cls.bss_hostapd = None
|
||||||
112
autotests/testPSK-roam/disconnect_during_handshake_test.py
Normal file
112
autotests/testPSK-roam/disconnect_during_handshake_test.py
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
#! /usr/bin/python3
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
import sys, os
|
||||||
|
|
||||||
|
sys.path.append('../util')
|
||||||
|
import iwd
|
||||||
|
from iwd import IWD
|
||||||
|
from iwd import PSKAgent
|
||||||
|
from iwd import NetworkType
|
||||||
|
from hwsim import Hwsim
|
||||||
|
from hostapd import HostapdCLI
|
||||||
|
import testutil
|
||||||
|
|
||||||
|
class Test(unittest.TestCase):
|
||||||
|
def validate_connection(self, wd):
|
||||||
|
device = wd.list_devices(1)[0]
|
||||||
|
|
||||||
|
ordered_network = device.get_ordered_network('TestFT', full_scan=True)
|
||||||
|
|
||||||
|
self.assertEqual(ordered_network.type, NetworkType.psk)
|
||||||
|
|
||||||
|
condition = 'not obj.connected'
|
||||||
|
wd.wait_for_object_condition(ordered_network.network_object, condition)
|
||||||
|
|
||||||
|
self.assertFalse(self.bss_hostapd[0].list_sta())
|
||||||
|
self.assertFalse(self.bss_hostapd[1].list_sta())
|
||||||
|
|
||||||
|
device.connect_bssid(self.bss_hostapd[0].bssid)
|
||||||
|
|
||||||
|
condition = 'obj.state == DeviceState.connected'
|
||||||
|
wd.wait_for_object_condition(device, condition)
|
||||||
|
|
||||||
|
self.bss_hostapd[0].wait_for_event('AP-STA-CONNECTED %s' % device.address)
|
||||||
|
|
||||||
|
testutil.test_iface_operstate(device.name)
|
||||||
|
testutil.test_ifaces_connected(self.bss_hostapd[0].ifname, device.name)
|
||||||
|
self.assertRaises(Exception, testutil.test_ifaces_connected,
|
||||||
|
(self.bss_hostapd[1].ifname, device.name, True, True))
|
||||||
|
|
||||||
|
self.rule0.enabled = True
|
||||||
|
|
||||||
|
device.roam(self.bss_hostapd[1].bssid)
|
||||||
|
|
||||||
|
device.clear_events()
|
||||||
|
device.wait_for_event("handshake-started")
|
||||||
|
self.bss_hostapd[1].deauthenticate(device.address, reason=15, test=1)
|
||||||
|
|
||||||
|
# Check that iwd is on BSS 1 once out of roaming state and doesn't
|
||||||
|
# go through 'disconnected', 'autoconnect', 'connecting' in between
|
||||||
|
from_condition = 'obj.state == DeviceState.roaming'
|
||||||
|
to_condition = 'obj.state == DeviceState.disconnected'
|
||||||
|
wd.wait_for_object_change(device, from_condition, to_condition)
|
||||||
|
|
||||||
|
def test_disconnect_during_handshake(self):
|
||||||
|
self.bss_hostapd[0].set_value('wpa_key_mgmt', 'WPA-PSK')
|
||||||
|
self.bss_hostapd[0].reload()
|
||||||
|
self.bss_hostapd[0].wait_for_event("AP-ENABLED")
|
||||||
|
|
||||||
|
self.bss_hostapd[1].set_value('wpa_key_mgmt', 'WPA-PSK')
|
||||||
|
self.bss_hostapd[1].reload()
|
||||||
|
self.bss_hostapd[1].wait_for_event("AP-ENABLED")
|
||||||
|
|
||||||
|
self.validate_connection(self.wd)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" down')
|
||||||
|
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" down')
|
||||||
|
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" up')
|
||||||
|
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" up')
|
||||||
|
|
||||||
|
for hapd in self.bss_hostapd:
|
||||||
|
hapd.default()
|
||||||
|
|
||||||
|
self.wd.stop()
|
||||||
|
self.wd = None
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.wd = IWD(True)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls):
|
||||||
|
hwsim = Hwsim()
|
||||||
|
|
||||||
|
IWD.copy_to_storage('TestFT.psk')
|
||||||
|
|
||||||
|
cls.bss_hostapd = [ HostapdCLI(config='ft-psk-ccmp-1.conf'),
|
||||||
|
HostapdCLI(config='ft-psk-ccmp-2.conf') ]
|
||||||
|
|
||||||
|
unused = HostapdCLI(config='ft-psk-ccmp-3.conf')
|
||||||
|
unused.disable()
|
||||||
|
|
||||||
|
cls.bss_hostapd[0].set_address('12:00:00:00:00:01')
|
||||||
|
cls.bss_hostapd[1].set_address('12:00:00:00:00:02')
|
||||||
|
|
||||||
|
rad1 = hwsim.get_radio('rad1')
|
||||||
|
|
||||||
|
cls.rule0 = hwsim.rules.create()
|
||||||
|
cls.rule0.destination = rad1.addresses[0]
|
||||||
|
cls.rule0.prefix = '08'
|
||||||
|
cls.rule0.drop = True
|
||||||
|
|
||||||
|
HostapdCLI.group_neighbors(*cls.bss_hostapd)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def tearDownClass(cls):
|
||||||
|
IWD.clear_storage()
|
||||||
|
cls.bss_hostapd = None
|
||||||
|
cls.rule0.remove()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main(exit=True)
|
||||||
@ -149,6 +149,21 @@ class Test(unittest.TestCase):
|
|||||||
condition = 'obj.state == DeviceState.disconnected'
|
condition = 'obj.state == DeviceState.disconnected'
|
||||||
self.wd.wait_for_object_condition(device, condition)
|
self.wd.wait_for_object_condition(device, condition)
|
||||||
|
|
||||||
|
def test_ft_deauth_before_association(self):
|
||||||
|
self.rule2.enabled = True
|
||||||
|
self.rule3.enabled = True
|
||||||
|
|
||||||
|
device = self.wd.list_devices(1)[0]
|
||||||
|
|
||||||
|
self.connect(self.wd, device, self.bss_hostapd[0])
|
||||||
|
|
||||||
|
device.wait_for_event('ft-authenticating', timeout=60)
|
||||||
|
|
||||||
|
self.bss_hostapd[1].deauthenticate(device.address)
|
||||||
|
|
||||||
|
condition = 'obj.state == DeviceState.disconnected'
|
||||||
|
self.wd.wait_for_object_condition(device, condition)
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.wd = IWD(True)
|
self.wd = IWD(True)
|
||||||
|
|
||||||
@ -232,6 +247,9 @@ class Test(unittest.TestCase):
|
|||||||
cls.rule2.remove()
|
cls.rule2.remove()
|
||||||
cls.rule3.remove()
|
cls.rule3.remove()
|
||||||
cls.assoc_rule.remove()
|
cls.assoc_rule.remove()
|
||||||
|
cls.rule_bss0.remove()
|
||||||
|
cls.rule_bss1.remove()
|
||||||
|
cls.rule_bss2.remove()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main(exit=True)
|
unittest.main(exit=True)
|
||||||
|
|||||||
@ -13,7 +13,7 @@ wpa=2
|
|||||||
wpa_key_mgmt=FT-PSK
|
wpa_key_mgmt=FT-PSK
|
||||||
wpa_pairwise=CCMP
|
wpa_pairwise=CCMP
|
||||||
wpa_passphrase=EasilyGuessedPassword
|
wpa_passphrase=EasilyGuessedPassword
|
||||||
ieee80211w=1
|
ieee80211w=0
|
||||||
rsn_preauth=1
|
rsn_preauth=1
|
||||||
rsn_preauth_interfaces=lo
|
rsn_preauth_interfaces=lo
|
||||||
disable_pmksa_caching=0
|
disable_pmksa_caching=0
|
||||||
|
|||||||
@ -13,7 +13,7 @@ wpa=2
|
|||||||
wpa_key_mgmt=FT-PSK
|
wpa_key_mgmt=FT-PSK
|
||||||
wpa_pairwise=CCMP
|
wpa_pairwise=CCMP
|
||||||
wpa_passphrase=EasilyGuessedPassword
|
wpa_passphrase=EasilyGuessedPassword
|
||||||
ieee80211w=1
|
ieee80211w=0
|
||||||
rsn_preauth=1
|
rsn_preauth=1
|
||||||
rsn_preauth_interfaces=lo
|
rsn_preauth_interfaces=lo
|
||||||
disable_pmksa_caching=0
|
disable_pmksa_caching=0
|
||||||
|
|||||||
@ -13,7 +13,7 @@ wpa=2
|
|||||||
wpa_key_mgmt=FT-PSK
|
wpa_key_mgmt=FT-PSK
|
||||||
wpa_pairwise=CCMP
|
wpa_pairwise=CCMP
|
||||||
wpa_passphrase=EasilyGuessedPassword
|
wpa_passphrase=EasilyGuessedPassword
|
||||||
ieee80211w=1
|
ieee80211w=0
|
||||||
rsn_preauth=1
|
rsn_preauth=1
|
||||||
rsn_preauth_interfaces=lo
|
rsn_preauth_interfaces=lo
|
||||||
disable_pmksa_caching=0
|
disable_pmksa_caching=0
|
||||||
|
|||||||
@ -3,3 +3,6 @@ DisableMacAddressRandomization=true
|
|||||||
|
|
||||||
[General]
|
[General]
|
||||||
RoamRetryInterval=1
|
RoamRetryInterval=1
|
||||||
|
|
||||||
|
# For disconnect_during_handshake_test
|
||||||
|
ManagementFrameProtection=0
|
||||||
|
|||||||
@ -81,12 +81,21 @@ class Test(unittest.TestCase):
|
|||||||
cls.bss_hostapd[0].set_value('ocv', '0')
|
cls.bss_hostapd[0].set_value('ocv', '0')
|
||||||
cls.bss_hostapd[0].set_value('ieee80211w', '0')
|
cls.bss_hostapd[0].set_value('ieee80211w', '0')
|
||||||
|
|
||||||
|
rad0 = hwsim.get_radio('rad0')
|
||||||
|
rad1 = hwsim.get_radio('rad1')
|
||||||
|
|
||||||
cls.rule0 = hwsim.rules.create()
|
cls.rule0 = hwsim.rules.create()
|
||||||
cls.rule0.source = 'any'
|
cls.rule0.source = rad0.addresses[0]
|
||||||
cls.rule0.bidirectional = True
|
cls.rule0.bidirectional = True
|
||||||
cls.rule0.signal = -8000
|
cls.rule0.signal = -8000
|
||||||
cls.rule0.enabled = True
|
cls.rule0.enabled = True
|
||||||
|
|
||||||
|
cls.rule1 = hwsim.rules.create()
|
||||||
|
cls.rule1.source = rad1.addresses[0]
|
||||||
|
cls.rule1.bidirectional = True
|
||||||
|
cls.rule1.signal = -8500
|
||||||
|
cls.rule1.enabled = True
|
||||||
|
|
||||||
cls.bss_hostapd[0].set_address('12:00:00:00:00:01')
|
cls.bss_hostapd[0].set_address('12:00:00:00:00:01')
|
||||||
cls.bss_hostapd[1].set_address('12:00:00:00:00:02')
|
cls.bss_hostapd[1].set_address('12:00:00:00:00:02')
|
||||||
|
|
||||||
@ -95,6 +104,7 @@ class Test(unittest.TestCase):
|
|||||||
IWD.clear_storage()
|
IWD.clear_storage()
|
||||||
cls.bss_hostapd = None
|
cls.bss_hostapd = None
|
||||||
cls.rule0.remove()
|
cls.rule0.remove()
|
||||||
|
cls.rule1.remove()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main(exit=True)
|
unittest.main(exit=True)
|
||||||
|
|||||||
@ -17,7 +17,7 @@ from hwsim import Hwsim
|
|||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
# Normally the time between a failed roam attempt and the next roam attempt
|
# Normally the time between a failed roam attempt and the next roam attempt
|
||||||
# is 60 seconds (default RoamRetryInterval). Test that we retry roaming
|
# is 60 seconds (default RoamRetryInterval). Test that we retry roaming
|
||||||
# faster if the transision looks like this: LOW [roam] [same bss] HIGH LOW.
|
# faster if the transition looks like this: LOW [roam] [same bss] HIGH LOW.
|
||||||
def test_fast_retry(self):
|
def test_fast_retry(self):
|
||||||
hwsim = Hwsim()
|
hwsim = Hwsim()
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,7 @@ from hostapd import HostapdCLI
|
|||||||
from hwsim import Hwsim
|
from hwsim import Hwsim
|
||||||
|
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
# Test that we do not periodically retry roaming if the transision looks
|
# Test that we do not periodically retry roaming if the transition looks
|
||||||
# like this: LOW [roam] [new bss] HIGH.
|
# like this: LOW [roam] [new bss] HIGH.
|
||||||
def test_stop_retry(self):
|
def test_stop_retry(self):
|
||||||
hwsim = Hwsim()
|
hwsim = Hwsim()
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import testutil
|
|||||||
from config import ctx
|
from config import ctx
|
||||||
|
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
def validate_connection(self, wd, ft=True):
|
def validate_connection(self, wd, ft=True, check_used_pmksa=False):
|
||||||
device = wd.list_devices(1)[0]
|
device = wd.list_devices(1)[0]
|
||||||
|
|
||||||
# This won't guarantee all BSS's are found, but at least ensures that
|
# This won't guarantee all BSS's are found, but at least ensures that
|
||||||
@ -37,6 +37,14 @@ class Test(unittest.TestCase):
|
|||||||
self.assertRaises(Exception, testutil.test_ifaces_connected,
|
self.assertRaises(Exception, testutil.test_ifaces_connected,
|
||||||
(self.bss_hostapd[1].ifname, device.name, True, True))
|
(self.bss_hostapd[1].ifname, device.name, True, True))
|
||||||
|
|
||||||
|
# If PMKSA was used, hostapd should not include the sae_group key in
|
||||||
|
# its status for the station.
|
||||||
|
sta_status = self.bss_hostapd[0].sta_status(device.address)
|
||||||
|
if check_used_pmksa:
|
||||||
|
self.assertNotIn("sae_group", sta_status.keys())
|
||||||
|
else:
|
||||||
|
self.assertIn("sae_group", sta_status.keys())
|
||||||
|
|
||||||
device.roam(self.bss_hostapd[1].bssid)
|
device.roam(self.bss_hostapd[1].bssid)
|
||||||
|
|
||||||
# Check that iwd is on BSS 1 once out of roaming state and doesn't
|
# Check that iwd is on BSS 1 once out of roaming state and doesn't
|
||||||
@ -88,6 +96,31 @@ class Test(unittest.TestCase):
|
|||||||
|
|
||||||
self.validate_connection(wd, True)
|
self.validate_connection(wd, True)
|
||||||
|
|
||||||
|
def test_ft_roam_pmksa(self):
|
||||||
|
wd = IWD(True)
|
||||||
|
|
||||||
|
self.bss_hostapd[0].set_value('wpa_key_mgmt', 'FT-SAE SAE')
|
||||||
|
self.bss_hostapd[0].reload()
|
||||||
|
self.bss_hostapd[0].wait_for_event("AP-ENABLED")
|
||||||
|
self.bss_hostapd[1].set_value('wpa_key_mgmt', 'FT-SAE SAE')
|
||||||
|
self.bss_hostapd[1].reload()
|
||||||
|
self.bss_hostapd[1].wait_for_event("AP-ENABLED")
|
||||||
|
self.bss_hostapd[2].set_value('wpa_key_mgmt', 'FT-PSK')
|
||||||
|
self.bss_hostapd[2].reload()
|
||||||
|
self.bss_hostapd[2].wait_for_event("AP-ENABLED")
|
||||||
|
|
||||||
|
self.validate_connection(wd, True)
|
||||||
|
|
||||||
|
device = wd.list_devices(1)[0]
|
||||||
|
device.disconnect()
|
||||||
|
|
||||||
|
for hapd in self.bss_hostapd:
|
||||||
|
hapd.deauthenticate(device.address)
|
||||||
|
|
||||||
|
wd.wait(5)
|
||||||
|
|
||||||
|
self.validate_connection(wd, True, check_used_pmksa=True)
|
||||||
|
|
||||||
def test_reassociate_roam_success(self):
|
def test_reassociate_roam_success(self):
|
||||||
wd = IWD(True)
|
wd = IWD(True)
|
||||||
|
|
||||||
@ -103,6 +136,31 @@ class Test(unittest.TestCase):
|
|||||||
|
|
||||||
self.validate_connection(wd, False)
|
self.validate_connection(wd, False)
|
||||||
|
|
||||||
|
def test_reassociate_roam_pmksa(self):
|
||||||
|
wd = IWD(True)
|
||||||
|
|
||||||
|
self.bss_hostapd[0].set_value('wpa_key_mgmt', 'SAE')
|
||||||
|
self.bss_hostapd[0].reload()
|
||||||
|
self.bss_hostapd[0].wait_for_event("AP-ENABLED")
|
||||||
|
self.bss_hostapd[1].set_value('wpa_key_mgmt', 'SAE')
|
||||||
|
self.bss_hostapd[1].reload()
|
||||||
|
self.bss_hostapd[1].wait_for_event("AP-ENABLED")
|
||||||
|
self.bss_hostapd[2].set_value('wpa_key_mgmt', 'WPA-PSK')
|
||||||
|
self.bss_hostapd[2].reload()
|
||||||
|
self.bss_hostapd[2].wait_for_event("AP-ENABLED")
|
||||||
|
|
||||||
|
self.validate_connection(wd, False)
|
||||||
|
|
||||||
|
device = wd.list_devices(1)[0]
|
||||||
|
device.disconnect()
|
||||||
|
|
||||||
|
for hapd in self.bss_hostapd:
|
||||||
|
hapd.deauthenticate(device.address)
|
||||||
|
|
||||||
|
wd.wait(5)
|
||||||
|
|
||||||
|
self.validate_connection(wd, False, check_used_pmksa=True)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" down')
|
os.system('ip link set "' + self.bss_hostapd[0].ifname + '" down')
|
||||||
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" down')
|
os.system('ip link set "' + self.bss_hostapd[1].ifname + '" down')
|
||||||
|
|||||||
@ -52,12 +52,6 @@ class Test(unittest.TestCase):
|
|||||||
self.hostapd.wait_for_event("AP-ENABLED")
|
self.hostapd.wait_for_event("AP-ENABLED")
|
||||||
self.validate_connection(self.wd, "ssidSAE", self.hostapd, 19)
|
self.validate_connection(self.wd, "ssidSAE", self.hostapd, 19)
|
||||||
|
|
||||||
def test_SAE_force_group_19(self):
|
|
||||||
# Vendor data from APs which require group 19 be used first
|
|
||||||
self.hostapd.reload()
|
|
||||||
self.hostapd.wait_for_event("AP-ENABLED")
|
|
||||||
self.validate_connection(self.wd, "ssidSAE-default-group", self.hostapd_defgroup, 19)
|
|
||||||
|
|
||||||
def test_SAE_Group20(self):
|
def test_SAE_Group20(self):
|
||||||
self.hostapd.set_value('sae_groups', '20')
|
self.hostapd.set_value('sae_groups', '20')
|
||||||
self.hostapd.reload()
|
self.hostapd.reload()
|
||||||
@ -88,7 +82,6 @@ class Test(unittest.TestCase):
|
|||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
cls.hostapd = HostapdCLI(config='ssidSAE.conf')
|
cls.hostapd = HostapdCLI(config='ssidSAE.conf')
|
||||||
cls.hostapd_h2e = HostapdCLI(config='ssidSAE-H2E.conf')
|
cls.hostapd_h2e = HostapdCLI(config='ssidSAE-H2E.conf')
|
||||||
cls.hostapd_defgroup = HostapdCLI(config='ssidSAE-default-group.conf')
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def tearDownClass(cls):
|
def tearDownClass(cls):
|
||||||
|
|||||||
@ -13,7 +13,7 @@ import testutil
|
|||||||
|
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
|
|
||||||
def validate_connection(self, wd, rejected=False):
|
def validate_connection(self, wd, hostapd, rejected=False):
|
||||||
devices = wd.list_devices(1)
|
devices = wd.list_devices(1)
|
||||||
self.assertIsNotNone(devices)
|
self.assertIsNotNone(devices)
|
||||||
device = devices[0]
|
device = devices[0]
|
||||||
@ -29,14 +29,14 @@ class Test(unittest.TestCase):
|
|||||||
wd.wait(2)
|
wd.wait(2)
|
||||||
|
|
||||||
testutil.test_iface_operstate(intf=device.name)
|
testutil.test_iface_operstate(intf=device.name)
|
||||||
testutil.test_ifaces_connected(if0=device.name, if1=self.hostapd.ifname)
|
testutil.test_ifaces_connected(if0=device.name, if1=hostapd.ifname)
|
||||||
|
|
||||||
if not rejected:
|
if not rejected:
|
||||||
self.assertEqual(device.event_ocurred("ecc-group-rejected"), False)
|
self.assertEqual(device.event_ocurred("ecc-group-rejected"), False)
|
||||||
|
|
||||||
print(self.hostapd._get_status())
|
print(hostapd._get_status())
|
||||||
|
|
||||||
sta_status = self.hostapd.sta_status(device.address)
|
sta_status = hostapd.sta_status(device.address)
|
||||||
|
|
||||||
print(sta_status)
|
print(sta_status)
|
||||||
|
|
||||||
@ -51,22 +51,27 @@ class Test(unittest.TestCase):
|
|||||||
# - Connect, try only group 19
|
# - Connect, try only group 19
|
||||||
def test_auto_selection(self):
|
def test_auto_selection(self):
|
||||||
IWD.copy_to_storage("profiles/ssidSAE.psk.default", name="ssidSAE.psk")
|
IWD.copy_to_storage("profiles/ssidSAE.psk.default", name="ssidSAE.psk")
|
||||||
self.validate_connection(self.wd, rejected=True)
|
self.validate_connection(self.wd, self.hostapd, rejected=True)
|
||||||
|
|
||||||
self.validate_connection(self.wd, rejected=False)
|
self.validate_connection(self.wd, self.hostapd, rejected=False)
|
||||||
|
|
||||||
# Try group 19 first
|
# Try group 19 first
|
||||||
def test_default_group_enabled(self):
|
def test_default_group_enabled(self):
|
||||||
IWD.copy_to_storage("profiles/ssidSAE.psk.default_group", name="ssidSAE.psk")
|
IWD.copy_to_storage("profiles/ssidSAE.psk.default_group", name="ssidSAE.psk")
|
||||||
self.validate_connection(self.wd)
|
self.validate_connection(self.wd, self.hostapd)
|
||||||
|
|
||||||
|
# Try group 19 first, with H2E
|
||||||
|
def test_default_group_enabled_h2e(self):
|
||||||
|
IWD.copy_to_storage("profiles/ssidSAE-H2E.psk.default_group", name="ssidSAE-H2E.psk")
|
||||||
|
self.validate_connection(self.wd, self.hostapd_h2e)
|
||||||
|
|
||||||
# Same as auto-selection but won't retain the default group setting
|
# Same as auto-selection but won't retain the default group setting
|
||||||
def test_default_group_disabled(self):
|
def test_default_group_disabled(self):
|
||||||
IWD.copy_to_storage("profiles/ssidSAE.psk.most_secure", name="ssidSAE.psk")
|
IWD.copy_to_storage("profiles/ssidSAE.psk.most_secure", name="ssidSAE.psk")
|
||||||
self.validate_connection(self.wd, rejected=True)
|
self.validate_connection(self.wd, self.hostapd, rejected=True)
|
||||||
|
|
||||||
# IWD should then retry but use only group 19
|
# IWD should then retry but use only group 19
|
||||||
self.validate_connection(self.wd, rejected=True)
|
self.validate_connection(self.wd, self.hostapd, rejected=True)
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.hostapd.default()
|
self.hostapd.default()
|
||||||
@ -88,6 +93,9 @@ class Test(unittest.TestCase):
|
|||||||
cls.hostapd = HostapdCLI(config='ssidSAE.conf')
|
cls.hostapd = HostapdCLI(config='ssidSAE.conf')
|
||||||
cls.hostapd.default()
|
cls.hostapd.default()
|
||||||
|
|
||||||
|
cls.hostapd_h2e = HostapdCLI(config='ssidSAE-H2E.conf')
|
||||||
|
cls.hostapd_h2e.default()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def tearDownClass(cls):
|
def tearDownClass(cls):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
[SETUP]
|
[SETUP]
|
||||||
num_radios=4
|
num_radios=3
|
||||||
start_iwd=0
|
start_iwd=0
|
||||||
hwsim_medium=yes
|
hwsim_medium=yes
|
||||||
|
|
||||||
[HOSTAPD]
|
[HOSTAPD]
|
||||||
rad0=ssidSAE.conf
|
rad0=ssidSAE.conf
|
||||||
rad1=ssidSAE-H2E.conf
|
rad1=ssidSAE-H2E.conf
|
||||||
rad2=ssidSAE-default-group.conf
|
|
||||||
|
|||||||
@ -4,3 +4,6 @@
|
|||||||
# hardware, but fails when used in simulated environment with mac80211_hwsim.
|
# hardware, but fails when used in simulated environment with mac80211_hwsim.
|
||||||
# Disable MAC randomization for the tests with hidden networks.
|
# Disable MAC randomization for the tests with hidden networks.
|
||||||
DisableMacAddressRandomization=true
|
DisableMacAddressRandomization=true
|
||||||
|
|
||||||
|
[General]
|
||||||
|
DisablePMKSA=true
|
||||||
|
|||||||
5
autotests/testSAE/profiles/ssidSAE-H2E.psk.default_group
Normal file
5
autotests/testSAE/profiles/ssidSAE-H2E.psk.default_group
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[Security]
|
||||||
|
Passphrase=secret123
|
||||||
|
|
||||||
|
[Settings]
|
||||||
|
UseDefaultEccGroup=true
|
||||||
@ -8,11 +8,12 @@ import iwd
|
|||||||
from iwd import IWD
|
from iwd import IWD
|
||||||
from iwd import PSKAgent
|
from iwd import PSKAgent
|
||||||
from iwd import NetworkType
|
from iwd import NetworkType
|
||||||
|
from hostapd import HostapdCLI
|
||||||
import testutil
|
import testutil
|
||||||
|
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
|
|
||||||
def test_connection_success(self):
|
def test_incorrect_password(self):
|
||||||
wd = IWD(True)
|
wd = IWD(True)
|
||||||
|
|
||||||
psk_agent = PSKAgent("InvalidPassword")
|
psk_agent = PSKAgent("InvalidPassword")
|
||||||
@ -34,6 +35,35 @@ class Test(unittest.TestCase):
|
|||||||
|
|
||||||
wd.unregister_psk_agent(psk_agent)
|
wd.unregister_psk_agent(psk_agent)
|
||||||
|
|
||||||
|
def test_deauth_after_connection(self):
|
||||||
|
wd = IWD(True)
|
||||||
|
hostapd = HostapdCLI(config="ssidWPA2.conf")
|
||||||
|
|
||||||
|
psk_agent = PSKAgent("secret123")
|
||||||
|
wd.register_psk_agent(psk_agent)
|
||||||
|
|
||||||
|
devices = wd.list_devices(1)
|
||||||
|
self.assertIsNotNone(devices)
|
||||||
|
device = devices[0]
|
||||||
|
|
||||||
|
ordered_network = device.get_ordered_network('ssidWPA2')
|
||||||
|
|
||||||
|
self.assertEqual(ordered_network.type, NetworkType.psk)
|
||||||
|
|
||||||
|
condition = 'not obj.connected'
|
||||||
|
wd.wait_for_object_condition(ordered_network.network_object, condition)
|
||||||
|
|
||||||
|
ordered_network.network_object.connect(wait=False)
|
||||||
|
|
||||||
|
device.wait_for_event("authenticating")
|
||||||
|
|
||||||
|
# Trigger a deauth just after authenticating
|
||||||
|
hostapd.deauthenticate(device.address)
|
||||||
|
|
||||||
|
device.wait_for_event("disconnected")
|
||||||
|
|
||||||
|
wd.unregister_psk_agent(psk_agent)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(cls):
|
def setUpClass(cls):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@ -184,8 +184,12 @@ class HostapdCLI(object):
|
|||||||
cmd = self.cmdline + ['wps_pin', 'any', pin]
|
cmd = self.cmdline + ['wps_pin', 'any', pin]
|
||||||
ctx.start_process(cmd).wait()
|
ctx.start_process(cmd).wait()
|
||||||
|
|
||||||
def deauthenticate(self, client_address):
|
def deauthenticate(self, client_address, reason=None, test=None):
|
||||||
cmd = self.cmdline + ['deauthenticate', client_address]
|
cmd = self.cmdline + ['deauthenticate', client_address]
|
||||||
|
|
||||||
|
if reason:
|
||||||
|
cmd.append(f"reason={reason} test={test}")
|
||||||
|
|
||||||
ctx.start_process(cmd).wait()
|
ctx.start_process(cmd).wait()
|
||||||
|
|
||||||
def eapol_reauth(self, client_address):
|
def eapol_reauth(self, client_address):
|
||||||
@ -284,13 +288,15 @@ class HostapdCLI(object):
|
|||||||
cmd = 'RESEND_M3 %s' % address
|
cmd = 'RESEND_M3 %s' % address
|
||||||
self.ctrl_sock.sendall(cmd.encode('utf-8'))
|
self.ctrl_sock.sendall(cmd.encode('utf-8'))
|
||||||
|
|
||||||
def chan_switch(self, channel):
|
def chan_switch(self, channel, wait=True):
|
||||||
if channel > len(chan_freq_map):
|
if channel > len(chan_freq_map):
|
||||||
raise Exception("Only 2.4GHz channels supported for chan_switch")
|
raise Exception("Only 2.4GHz channels supported for chan_switch")
|
||||||
|
|
||||||
cmd = self.cmdline + ['chan_switch', '50', str(chan_freq_map[channel])]
|
cmd = self.cmdline + ['chan_switch', '50', str(chan_freq_map[channel])]
|
||||||
ctx.start_process(cmd).wait()
|
ctx.start_process(cmd).wait()
|
||||||
self.wait_for_event('AP-CSA-FINISHED')
|
|
||||||
|
if wait:
|
||||||
|
self.wait_for_event('AP-CSA-FINISHED')
|
||||||
|
|
||||||
def _get_status(self):
|
def _get_status(self):
|
||||||
ret = {}
|
ret = {}
|
||||||
@ -364,3 +370,7 @@ class HostapdCLI(object):
|
|||||||
others = [h for h in args if h != hapd]
|
others = [h for h in args if h != hapd]
|
||||||
|
|
||||||
hapd._add_neighbors(*others)
|
hapd._add_neighbors(*others)
|
||||||
|
|
||||||
|
def pmksa_flush(self):
|
||||||
|
cmd = self.cmdline + ['pmksa_flush']
|
||||||
|
ctx.start_process(cmd).wait()
|
||||||
|
|||||||
@ -7,7 +7,10 @@ from weakref import WeakValueDictionary
|
|||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from scapy.all import *
|
from scapy.all import *
|
||||||
from scapy.contrib.wpa_eapol import WPA_key
|
try:
|
||||||
|
from scapy.contrib.wpa_eapol import WPA_key
|
||||||
|
except:
|
||||||
|
from scapy.layers.eap import EAPOL_KEY
|
||||||
|
|
||||||
import iwd
|
import iwd
|
||||||
from config import ctx
|
from config import ctx
|
||||||
@ -444,9 +447,15 @@ class Hwsim(iwd.AsyncOpAbstract):
|
|||||||
|
|
||||||
# NOTE: Expected key_info is 0x008a, with the install flag
|
# NOTE: Expected key_info is 0x008a, with the install flag
|
||||||
# this becomes 0x00ca.
|
# this becomes 0x00ca.
|
||||||
eapol = WPA_key( descriptor_type = 2,
|
try:
|
||||||
key_info = 0x00ca, # Includes an invalid install flag!
|
eapol = WPA_key( descriptor_type = 2,
|
||||||
replay_counter = struct.pack(">Q", 100))
|
key_info = 0x00ca, # Includes an invalid install flag!
|
||||||
|
replay_counter = struct.pack(">Q", 100))
|
||||||
|
except:
|
||||||
|
eapol = EAPOL_KEY( key_descriptor_type = 2,
|
||||||
|
install = 1,
|
||||||
|
key_ack = 1,
|
||||||
|
key_replay_counter = 1)
|
||||||
frame /= LLC()/SNAP()/EAPOL(version="802.1X-2004", type="EAPOL-Key")
|
frame /= LLC()/SNAP()/EAPOL(version="802.1X-2004", type="EAPOL-Key")
|
||||||
frame /= eapol
|
frame /= eapol
|
||||||
|
|
||||||
|
|||||||
@ -112,8 +112,8 @@ class AsyncOpAbstract(object):
|
|||||||
self._is_completed = True
|
self._is_completed = True
|
||||||
self._exception = _convert_dbus_ex(ex)
|
self._exception = _convert_dbus_ex(ex)
|
||||||
|
|
||||||
def _wait_for_async_op(self):
|
def _wait_for_async_op(self, timeout=50):
|
||||||
ctx.non_block_wait(lambda s: s._is_completed, 30, self, exception=None)
|
ctx.non_block_wait(lambda s: s._is_completed, timeout, self, exception=None)
|
||||||
|
|
||||||
self._is_completed = False
|
self._is_completed = False
|
||||||
if self._exception is not None:
|
if self._exception is not None:
|
||||||
@ -280,8 +280,15 @@ class StationDebug(IWDDBusAbstract):
|
|||||||
def autoconnect(self):
|
def autoconnect(self):
|
||||||
return self._properties['AutoConnect']
|
return self._properties['AutoConnect']
|
||||||
|
|
||||||
def connect_bssid(self, address):
|
def connect_bssid(self, address, wait=True):
|
||||||
self._iface.ConnectBssid(dbus.ByteArray.fromhex(address.replace(':', '')))
|
self._iface.ConnectBssid(
|
||||||
|
dbus.ByteArray.fromhex(address.replace(':', '')),
|
||||||
|
reply_handler=self._success,
|
||||||
|
error_handler=self._failure
|
||||||
|
)
|
||||||
|
|
||||||
|
if wait:
|
||||||
|
self._wait_for_async_op()
|
||||||
|
|
||||||
def roam(self, address):
|
def roam(self, address):
|
||||||
self._iface.Roam(dbus.ByteArray.fromhex(address.replace(':', '')))
|
self._iface.Roam(dbus.ByteArray.fromhex(address.replace(':', '')))
|
||||||
@ -299,6 +306,9 @@ class StationDebug(IWDDBusAbstract):
|
|||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def clear_events(self):
|
||||||
|
self._events = []
|
||||||
|
|
||||||
def wait_for_event(self, event, timeout=10):
|
def wait_for_event(self, event, timeout=10):
|
||||||
return ctx.non_block_wait(self._poll_event, timeout, event,
|
return ctx.non_block_wait(self._poll_event, timeout, event,
|
||||||
exception=TimeoutError("waiting for event"))
|
exception=TimeoutError("waiting for event"))
|
||||||
@ -447,13 +457,15 @@ class Device(IWDDBusAbstract):
|
|||||||
self._wps_manager_if = None
|
self._wps_manager_if = None
|
||||||
self._station_if = None
|
self._station_if = None
|
||||||
self._station_props = None
|
self._station_props = None
|
||||||
self._station_debug_obj = None
|
|
||||||
self._dpp_obj = None
|
self._dpp_obj = None
|
||||||
self._sc_dpp_obj = None
|
self._sc_dpp_obj = None
|
||||||
self._ap_obj = None
|
self._ap_obj = None
|
||||||
|
|
||||||
IWDDBusAbstract.__init__(self, *args, **kwargs)
|
IWDDBusAbstract.__init__(self, *args, **kwargs)
|
||||||
|
|
||||||
|
self._station_debug_obj = StationDebug(object_path=self._object_path,
|
||||||
|
namespace=self._namespace)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _wps_manager(self):
|
def _wps_manager(self):
|
||||||
if self._wps_manager_if is None:
|
if self._wps_manager_if is None:
|
||||||
@ -593,6 +605,11 @@ class Device(IWDDBusAbstract):
|
|||||||
props = self._station_properties()
|
props = self._station_properties()
|
||||||
return props.get('ConnectedNetwork')
|
return props.get('ConnectedNetwork')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def connected_bss(self):
|
||||||
|
props = self._station_properties()
|
||||||
|
return props.get('ConnectedAccessPoint')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def powered(self):
|
def powered(self):
|
||||||
'''
|
'''
|
||||||
@ -627,6 +644,19 @@ class Device(IWDDBusAbstract):
|
|||||||
self._station_debug._prop_proxy.Set(IWD_STATION_DEBUG_INTERFACE,
|
self._station_debug._prop_proxy.Set(IWD_STATION_DEBUG_INTERFACE,
|
||||||
'AutoConnect', value)
|
'AutoConnect', value)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def affinities(self):
|
||||||
|
return self._station_properties()['Affinities']
|
||||||
|
|
||||||
|
@affinities.setter
|
||||||
|
def affinities(self, values):
|
||||||
|
self._station_properties()
|
||||||
|
self._station_prop_if.Set(
|
||||||
|
IWD_STATION_INTERFACE, 'Affinities',
|
||||||
|
dbus.Array([dbus.ObjectPath(v) for v in values], signature="o"),
|
||||||
|
reply_handler=self._success, error_handler=self._failure)
|
||||||
|
self._wait_for_async_op()
|
||||||
|
|
||||||
def scan(self, wait=True):
|
def scan(self, wait=True):
|
||||||
'''Schedule a network scan.
|
'''Schedule a network scan.
|
||||||
|
|
||||||
@ -847,8 +877,8 @@ class Device(IWDDBusAbstract):
|
|||||||
def stop_adhoc(self):
|
def stop_adhoc(self):
|
||||||
self._prop_proxy.Set(IWD_DEVICE_INTERFACE, 'Mode', 'station')
|
self._prop_proxy.Set(IWD_DEVICE_INTERFACE, 'Mode', 'station')
|
||||||
|
|
||||||
def connect_bssid(self, address):
|
def connect_bssid(self, address, wait=True):
|
||||||
self._station_debug.connect_bssid(address)
|
self._station_debug.connect_bssid(address, wait=wait)
|
||||||
|
|
||||||
def roam(self, address):
|
def roam(self, address):
|
||||||
self._station_debug.roam(address)
|
self._station_debug.roam(address)
|
||||||
@ -859,6 +889,9 @@ class Device(IWDDBusAbstract):
|
|||||||
def wait_for_event(self, event, timeout=10):
|
def wait_for_event(self, event, timeout=10):
|
||||||
self._station_debug.wait_for_event(event, timeout)
|
self._station_debug.wait_for_event(event, timeout)
|
||||||
|
|
||||||
|
def clear_events(self):
|
||||||
|
self._station_debug.clear_events()
|
||||||
|
|
||||||
def event_ocurred(self, event):
|
def event_ocurred(self, event):
|
||||||
return self._station_debug.event_ocurred(event)
|
return self._station_debug.event_ocurred(event)
|
||||||
|
|
||||||
@ -969,7 +1002,11 @@ class Network(IWDDBusAbstract):
|
|||||||
'''
|
'''
|
||||||
return bool(self._properties['Connected'])
|
return bool(self._properties['Connected'])
|
||||||
|
|
||||||
def connect(self, wait=True):
|
@property
|
||||||
|
def extended_service_set(self):
|
||||||
|
return self._properties['ExtendedServiceSet']
|
||||||
|
|
||||||
|
def connect(self, wait=True, timeout=50, reply_handler=None, error_handler=None):
|
||||||
'''
|
'''
|
||||||
Connect to the network. Request the device implied by the object
|
Connect to the network. Request the device implied by the object
|
||||||
path to connect to specified network.
|
path to connect to specified network.
|
||||||
@ -984,12 +1021,19 @@ class Network(IWDDBusAbstract):
|
|||||||
@rtype: void
|
@rtype: void
|
||||||
'''
|
'''
|
||||||
|
|
||||||
|
if not reply_handler:
|
||||||
|
reply_handler = self._success
|
||||||
|
|
||||||
|
if not error_handler:
|
||||||
|
error_handler = self._failure
|
||||||
|
|
||||||
self._iface.Connect(dbus_interface=self._iface_name,
|
self._iface.Connect(dbus_interface=self._iface_name,
|
||||||
reply_handler=self._success,
|
reply_handler=reply_handler,
|
||||||
error_handler=self._failure)
|
error_handler=error_handler,
|
||||||
|
timeout=timeout)
|
||||||
|
|
||||||
if wait:
|
if wait:
|
||||||
self._wait_for_async_op()
|
self._wait_for_async_op(timeout=timeout)
|
||||||
|
|
||||||
def __str__(self, prefix = ''):
|
def __str__(self, prefix = ''):
|
||||||
return prefix + 'Network:\n' \
|
return prefix + 'Network:\n' \
|
||||||
@ -1453,10 +1497,10 @@ class IWD(AsyncOpAbstract):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create_in_storage(file_name, file_content, storage_dir=IWD_STORAGE_DIR):
|
def create_in_storage(file_name, file_content, storage_dir=IWD_STORAGE_DIR):
|
||||||
fo = open(storage_dir + '/' + file_name, 'w')
|
f = open(storage_dir + '/' + file_name, 'w')
|
||||||
|
|
||||||
fo.write(file_content)
|
f.write(file_content)
|
||||||
fo.close()
|
f.close()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _ensure_storage_dir_exists(storage_dir):
|
def _ensure_storage_dir_exists(storage_dir):
|
||||||
|
|||||||
@ -237,7 +237,7 @@ class Wpas:
|
|||||||
('' if go_intent is None else ' go_intent=' + str(go_intent)))
|
('' if go_intent is None else ' go_intent=' + str(go_intent)))
|
||||||
self.wait_for_event('OK')
|
self.wait_for_event('OK')
|
||||||
|
|
||||||
# Pre-accept the next GO Negotiation Request from this peer to avoid the extra Respone + Request frames
|
# Pre-accept the next GO Negotiation Request from this peer to avoid the extra Response + Request frames
|
||||||
def p2p_authorize(self, peer, pin=None, go_intent=None):
|
def p2p_authorize(self, peer, pin=None, go_intent=None):
|
||||||
self._rx_data = []
|
self._rx_data = []
|
||||||
self._ctrl_request('P2P_CONNECT ' + peer['p2p_dev_addr'] + ' ' + ('pbc' if pin is None else pin) +
|
self._ctrl_request('P2P_CONNECT ' + peer['p2p_dev_addr'] + ' ' + ('pbc' if pin is None else pin) +
|
||||||
|
|||||||
109
client/bss.c
Normal file
109
client/bss.c
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* Wireless daemon for Linux
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024, Locus Robotics
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <ell/ell.h>
|
||||||
|
#include "ell/useful.h"
|
||||||
|
|
||||||
|
#include "client/dbus-proxy.h"
|
||||||
|
#include "client/display.h"
|
||||||
|
|
||||||
|
struct bss {
|
||||||
|
char *address;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *get_address(const void *data)
|
||||||
|
{
|
||||||
|
const struct bss *bss = data;
|
||||||
|
|
||||||
|
return bss->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_address(void *data, struct l_dbus_message_iter *variant)
|
||||||
|
{
|
||||||
|
struct bss *bss = data;
|
||||||
|
const char *value;
|
||||||
|
|
||||||
|
l_free(bss->address);
|
||||||
|
|
||||||
|
if (!l_dbus_message_iter_get_variant(variant, "s", &value)) {
|
||||||
|
bss->address = NULL;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bss->address = l_strdup(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct proxy_interface_property bss_properties[] = {
|
||||||
|
{ "Address", "s", update_address, get_address },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void *bss_create(void)
|
||||||
|
{
|
||||||
|
return l_new(struct bss, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bss_destroy(void *data)
|
||||||
|
{
|
||||||
|
struct bss *bss = data;
|
||||||
|
|
||||||
|
l_free(bss->address);
|
||||||
|
l_free(bss);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bss_display_inline(const char *margin, const void *data)
|
||||||
|
{
|
||||||
|
const struct bss *bss = data;
|
||||||
|
|
||||||
|
display("%s%s\n", margin, bss->address);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct proxy_interface_type_ops ops = {
|
||||||
|
.create = bss_create,
|
||||||
|
.destroy = bss_destroy,
|
||||||
|
.display = bss_display_inline,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct proxy_interface_type bss_interface_type = {
|
||||||
|
.interface = IWD_BSS_INTERFACE,
|
||||||
|
.properties = bss_properties,
|
||||||
|
.ops = &ops,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int bss_interface_init(void)
|
||||||
|
{
|
||||||
|
proxy_interface_type_register(&bss_interface_type);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void bss_interface_exit(void)
|
||||||
|
{
|
||||||
|
proxy_interface_type_unregister(&bss_interface_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
INTERFACE_TYPE(bss_interface_type, bss_interface_init, bss_interface_exit)
|
||||||
@ -47,10 +47,10 @@ static struct l_dbus *dbus;
|
|||||||
static struct l_queue *proxy_interfaces;
|
static struct l_queue *proxy_interfaces;
|
||||||
static struct l_queue *proxy_interface_types;
|
static struct l_queue *proxy_interface_types;
|
||||||
|
|
||||||
void proxy_properties_display(const struct proxy_interface *proxy,
|
void proxy_properties_display_inline(const struct proxy_interface *proxy,
|
||||||
const char *caption, const char *margin,
|
const char *margin,
|
||||||
unsigned int name_column_width,
|
unsigned int name_column_width,
|
||||||
unsigned int value_column_width)
|
unsigned int value_column_width)
|
||||||
{
|
{
|
||||||
const void *data;
|
const void *data;
|
||||||
const struct proxy_interface_property *properties;
|
const struct proxy_interface_property *properties;
|
||||||
@ -59,11 +59,6 @@ void proxy_properties_display(const struct proxy_interface *proxy,
|
|||||||
if (!proxy->type->properties)
|
if (!proxy->type->properties)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
display_table_header(caption, "%s%-*s %-*s %-*s", margin,
|
|
||||||
8, "Settable",
|
|
||||||
name_column_width, "Property",
|
|
||||||
value_column_width, "Value");
|
|
||||||
|
|
||||||
data = proxy_interface_get_data(proxy);
|
data = proxy_interface_get_data(proxy);
|
||||||
properties = proxy->type->properties;
|
properties = proxy->type->properties;
|
||||||
|
|
||||||
@ -82,6 +77,31 @@ void proxy_properties_display(const struct proxy_interface *proxy,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void proxy_properties_display_header(const char *caption, const char *margin,
|
||||||
|
unsigned int name_column_width,
|
||||||
|
unsigned int value_column_width)
|
||||||
|
{
|
||||||
|
display_table_header(caption, "%s%-*s %-*s %-*s", margin,
|
||||||
|
8, "Settable",
|
||||||
|
name_column_width, "Property",
|
||||||
|
value_column_width, "Value");
|
||||||
|
}
|
||||||
|
|
||||||
|
void proxy_properties_display(const struct proxy_interface *proxy,
|
||||||
|
const char *caption, const char *margin,
|
||||||
|
unsigned int name_column_width,
|
||||||
|
unsigned int value_column_width)
|
||||||
|
{
|
||||||
|
if (!proxy->type->properties)
|
||||||
|
return;
|
||||||
|
|
||||||
|
proxy_properties_display_header(caption, margin, name_column_width,
|
||||||
|
value_column_width);
|
||||||
|
|
||||||
|
proxy_properties_display_inline(proxy, margin, name_column_width,
|
||||||
|
value_column_width);
|
||||||
|
}
|
||||||
|
|
||||||
static const void *proxy_interface_property_tostr(
|
static const void *proxy_interface_property_tostr(
|
||||||
const struct proxy_interface *proxy,
|
const struct proxy_interface *proxy,
|
||||||
const char *name)
|
const char *name)
|
||||||
|
|||||||
@ -41,6 +41,7 @@ struct proxy_interface;
|
|||||||
#define IWD_DPP_INTERFACE "net.connman.iwd.DeviceProvisioning"
|
#define IWD_DPP_INTERFACE "net.connman.iwd.DeviceProvisioning"
|
||||||
#define IWD_DPP_PKEX_INTERFACE \
|
#define IWD_DPP_PKEX_INTERFACE \
|
||||||
"net.connman.iwd.SharedCodeDeviceProvisioning"
|
"net.connman.iwd.SharedCodeDeviceProvisioning"
|
||||||
|
#define IWD_BSS_INTERFACE "net.connman.iwd.BasicServiceSet"
|
||||||
|
|
||||||
typedef bool (*proxy_property_match_func_t) (const void *a, const void *b);
|
typedef bool (*proxy_property_match_func_t) (const void *a, const void *b);
|
||||||
|
|
||||||
@ -95,6 +96,13 @@ void proxy_properties_display(const struct proxy_interface *proxy,
|
|||||||
const char *caption, const char *margin,
|
const char *caption, const char *margin,
|
||||||
unsigned int name_column_width,
|
unsigned int name_column_width,
|
||||||
unsigned int value_column_width);
|
unsigned int value_column_width);
|
||||||
|
void proxy_properties_display_inline(const struct proxy_interface *proxy,
|
||||||
|
const char *margin,
|
||||||
|
unsigned int name_column_width,
|
||||||
|
unsigned int value_column_width);
|
||||||
|
void proxy_properties_display_header(const char *caption, const char *margin,
|
||||||
|
unsigned int name_column_width,
|
||||||
|
unsigned int value_column_width);
|
||||||
|
|
||||||
char *proxy_property_str_completion(const struct proxy_interface_type *type,
|
char *proxy_property_str_completion(const struct proxy_interface_type *type,
|
||||||
proxy_property_match_func_t function,
|
proxy_property_match_func_t function,
|
||||||
|
|||||||
@ -95,6 +95,8 @@ static const struct diagnostic_dict_mapping diagnostic_mapping[] = {
|
|||||||
{ "Frequency", 'u' },
|
{ "Frequency", 'u' },
|
||||||
{ "Channel", 'q' },
|
{ "Channel", 'q' },
|
||||||
{ "Security", 's' },
|
{ "Security", 's' },
|
||||||
|
{ "InactiveTime", 'u', "ms" },
|
||||||
|
{ "ConnectedTime", 'u', "s" },
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -186,5 +188,5 @@ void diagnostic_display(struct l_dbus_message_iter *dict,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
parse_error:
|
parse_error:
|
||||||
display_error("Error parsing dignostics");
|
display_error("Error parsing diagnostics");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,6 +35,7 @@ struct network {
|
|||||||
char *identity;
|
char *identity;
|
||||||
char *name;
|
char *name;
|
||||||
char *type;
|
char *type;
|
||||||
|
struct l_queue *bss_list;
|
||||||
const struct proxy_interface *device;
|
const struct proxy_interface *device;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -146,11 +147,58 @@ static void update_type(void *data, struct l_dbus_message_iter *variant)
|
|||||||
network->type = l_strdup(value);
|
network->type = l_strdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool match_path(const void *a, const void *user_data)
|
||||||
|
{
|
||||||
|
const char *path1 = a;
|
||||||
|
const char *path2 = user_data;
|
||||||
|
|
||||||
|
return !strcmp(path1, path2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_ess(void *data, struct l_dbus_message_iter *variant)
|
||||||
|
{
|
||||||
|
struct network *network = data;
|
||||||
|
struct l_dbus_message_iter array;
|
||||||
|
const char *path;
|
||||||
|
|
||||||
|
if (!network->bss_list)
|
||||||
|
network->bss_list = l_queue_new();
|
||||||
|
|
||||||
|
if (!l_dbus_message_iter_get_variant(variant, "ao", &array))
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (l_dbus_message_iter_next_entry(&array, &path)) {
|
||||||
|
l_free(l_queue_remove_if(network->bss_list, match_path, path));
|
||||||
|
l_queue_push_head(network->bss_list, l_strdup(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *get_ess(const void *data)
|
||||||
|
{
|
||||||
|
const struct network *network = data;
|
||||||
|
static char count[10];
|
||||||
|
|
||||||
|
snprintf(count, 10, "Count %u", l_queue_length(network->bss_list));
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct l_queue *network_get_bss_list(
|
||||||
|
const struct proxy_interface *network_proxy)
|
||||||
|
{
|
||||||
|
const struct network *network = proxy_interface_get_data(network_proxy);
|
||||||
|
if (!network)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return network->bss_list;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct proxy_interface_property network_properties[] = {
|
static const struct proxy_interface_property network_properties[] = {
|
||||||
{ "Name", "s", update_name, get_name },
|
{ "Name", "s", update_name, get_name },
|
||||||
{ "Connected", "b", update_connected},
|
{ "Connected", "b", update_connected},
|
||||||
{ "Device", "o", update_device},
|
{ "Device", "o", update_device},
|
||||||
{ "Type", "s", update_type},
|
{ "Type", "s", update_type},
|
||||||
|
{ "ExtendedServiceSet", "ao", update_ess, get_ess },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -171,7 +219,7 @@ static void network_display_inline(const char *margin, const void *data)
|
|||||||
|
|
||||||
display("%s%s %s %s\n", margin, network->name ? network->name : "",
|
display("%s%s %s %s\n", margin, network->name ? network->name : "",
|
||||||
network->type ? network->type : "",
|
network->type ? network->type : "",
|
||||||
network->connected ? "connected" : "diconnected");
|
network->connected ? "connected" : "disconnected");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *network_create(void)
|
static void *network_create(void)
|
||||||
@ -186,6 +234,7 @@ static void network_destroy(void *data)
|
|||||||
l_free(network->name);
|
l_free(network->name);
|
||||||
l_free(network->type);
|
l_free(network->type);
|
||||||
l_free(network->identity);
|
l_free(network->identity);
|
||||||
|
l_queue_destroy(network->bss_list, l_free);
|
||||||
|
|
||||||
network->device = NULL;
|
network->device = NULL;
|
||||||
|
|
||||||
|
|||||||
@ -37,3 +37,5 @@ char *network_name_completion(const struct proxy_interface *device,
|
|||||||
struct l_queue *network_match_by_device_and_args(
|
struct l_queue *network_match_by_device_and_args(
|
||||||
const struct proxy_interface *device,
|
const struct proxy_interface *device,
|
||||||
const struct network_args *args);
|
const struct network_args *args);
|
||||||
|
struct l_queue *network_get_bss_list(
|
||||||
|
const struct proxy_interface *network_proxy);
|
||||||
|
|||||||
@ -175,8 +175,8 @@ static void display_addresses(const char *device_name)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
have_address = true;
|
have_address = true;
|
||||||
display("%s%*s %-*s%-*s\n", MARGIN, 8, "", 20,
|
display_table_row(MARGIN, 3, 8, "", 20,
|
||||||
"IPv6 address", 47, addrstr);
|
"IPv6 address", 47, addrstr);
|
||||||
} else if (cur->ifa_addr->sa_family == AF_INET) {
|
} else if (cur->ifa_addr->sa_family == AF_INET) {
|
||||||
struct sockaddr_in *si =
|
struct sockaddr_in *si =
|
||||||
(struct sockaddr_in *) cur->ifa_addr;
|
(struct sockaddr_in *) cur->ifa_addr;
|
||||||
@ -283,28 +283,26 @@ static char *connect_cmd_arg_completion(const char *text, int state,
|
|||||||
return network_name_completion(device, text, state);
|
return network_name_completion(device, text, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum cmd_status cmd_connect(const char *device_name,
|
static const struct proxy_interface *find_network(const char *device_name,
|
||||||
char **argv, int argc)
|
const char *name,
|
||||||
|
const char *type)
|
||||||
{
|
{
|
||||||
struct network_args network_args;
|
struct network_args network_args;
|
||||||
struct l_queue *match;
|
struct l_queue *match;
|
||||||
const struct proxy_interface *network_proxy;
|
const struct proxy_interface *network_proxy;
|
||||||
const struct proxy_interface *device_proxy;
|
const struct proxy_interface *device_proxy;
|
||||||
|
|
||||||
if (argc < 1)
|
|
||||||
return CMD_STATUS_INVALID_ARGS;
|
|
||||||
|
|
||||||
device_proxy = device_proxy_find_by_name(device_name);
|
device_proxy = device_proxy_find_by_name(device_name);
|
||||||
if (!device_proxy)
|
if (!device_proxy)
|
||||||
return CMD_STATUS_INVALID_VALUE;
|
return NULL;
|
||||||
|
|
||||||
network_args.name = argv[0];
|
network_args.name = name;
|
||||||
network_args.type = argc >= 2 ? argv[1] : NULL;
|
network_args.type = type;
|
||||||
|
|
||||||
match = network_match_by_device_and_args(device_proxy, &network_args);
|
match = network_match_by_device_and_args(device_proxy, &network_args);
|
||||||
if (!match) {
|
if (!match) {
|
||||||
display("Invalid network name '%s'\n", network_args.name);
|
display("Invalid network name '%s'\n", network_args.name);
|
||||||
return CMD_STATUS_INVALID_VALUE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l_queue_length(match) > 1) {
|
if (l_queue_length(match) > 1) {
|
||||||
@ -315,11 +313,28 @@ static enum cmd_status cmd_connect(const char *device_name,
|
|||||||
|
|
||||||
l_queue_destroy(match, NULL);
|
l_queue_destroy(match, NULL);
|
||||||
|
|
||||||
return CMD_STATUS_INVALID_VALUE;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
network_proxy = l_queue_pop_head(match);
|
network_proxy = l_queue_pop_head(match);
|
||||||
l_queue_destroy(match, NULL);
|
l_queue_destroy(match, NULL);
|
||||||
|
|
||||||
|
return network_proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum cmd_status cmd_connect(const char *device_name,
|
||||||
|
char **argv, int argc)
|
||||||
|
{
|
||||||
|
const struct proxy_interface *network_proxy;
|
||||||
|
|
||||||
|
if (argc < 1)
|
||||||
|
return CMD_STATUS_INVALID_ARGS;
|
||||||
|
|
||||||
|
network_proxy = find_network(device_name, argv[0],
|
||||||
|
argc >= 2 ? argv[1] : NULL);
|
||||||
|
if (!network_proxy)
|
||||||
|
return CMD_STATUS_INVALID_VALUE;
|
||||||
|
|
||||||
network_connect(network_proxy);
|
network_connect(network_proxy);
|
||||||
|
|
||||||
return CMD_STATUS_TRIGGERED;
|
return CMD_STATUS_TRIGGERED;
|
||||||
@ -708,6 +723,55 @@ static enum cmd_status cmd_show(const char *device_name,
|
|||||||
return CMD_STATUS_TRIGGERED;
|
return CMD_STATUS_TRIGGERED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static enum cmd_status cmd_get_bsses(const char *device_name,
|
||||||
|
char **argv, int argc)
|
||||||
|
{
|
||||||
|
const struct proxy_interface *station_i =
|
||||||
|
device_proxy_find(device_name, IWD_STATION_INTERFACE);
|
||||||
|
const struct station *station = proxy_interface_get_data(station_i);
|
||||||
|
struct l_queue *bss_list;
|
||||||
|
const struct l_queue_entry *e;
|
||||||
|
const struct proxy_interface *network_proxy;
|
||||||
|
char header[256];
|
||||||
|
|
||||||
|
if (argc > 0)
|
||||||
|
network_proxy = find_network(device_name, argv[0],
|
||||||
|
argc >= 2 ? argv[1] : NULL);
|
||||||
|
else
|
||||||
|
network_proxy = station->connected_network;
|
||||||
|
|
||||||
|
if (!network_proxy) {
|
||||||
|
display_error("Can't find network");
|
||||||
|
return CMD_STATUS_INVALID_ARGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bss_list = network_get_bss_list(network_proxy);
|
||||||
|
if (!bss_list) {
|
||||||
|
display_error("No BSS list for network");
|
||||||
|
return CMD_STATUS_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(header, "%s BasicServiceSets", network_get_name(network_proxy));
|
||||||
|
|
||||||
|
proxy_properties_display_header(header, MARGIN, 10, 18);
|
||||||
|
|
||||||
|
for (e = l_queue_get_entries(bss_list); e; e = e->next) {
|
||||||
|
const char *path = e->data;
|
||||||
|
const struct proxy_interface *bss_i = proxy_interface_find(
|
||||||
|
IWD_BSS_INTERFACE, path);
|
||||||
|
|
||||||
|
if (!bss_i)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
display_table_row(MARGIN, 1, strlen(path), path);
|
||||||
|
proxy_properties_display_inline(bss_i, MARGIN, 10, 18);
|
||||||
|
display_table_row(MARGIN, 1, 1, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_STATUS_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct command station_commands[] = {
|
static const struct command station_commands[] = {
|
||||||
{ NULL, "list", NULL, cmd_list, "List devices in Station mode", true },
|
{ NULL, "list", NULL, cmd_list, "List devices in Station mode", true },
|
||||||
{ "<wlan>", "connect",
|
{ "<wlan>", "connect",
|
||||||
@ -732,6 +796,8 @@ static const struct command station_commands[] = {
|
|||||||
"Get hidden APs", true },
|
"Get hidden APs", true },
|
||||||
{ "<wlan>", "scan", NULL, cmd_scan, "Scan for networks" },
|
{ "<wlan>", "scan", NULL, cmd_scan, "Scan for networks" },
|
||||||
{ "<wlan>", "show", NULL, cmd_show, "Show station info", true },
|
{ "<wlan>", "show", NULL, cmd_show, "Show station info", true },
|
||||||
|
{ "<wlan>", "get-bsses", "[network] [security]", cmd_get_bsses,
|
||||||
|
"Get BSS's for a network", true },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
AC_PREREQ([2.69])
|
AC_PREREQ([2.69])
|
||||||
AC_INIT([iwd],[2.17])
|
AC_INIT([iwd],[3.10])
|
||||||
|
|
||||||
AC_CONFIG_HEADERS(config.h)
|
AC_CONFIG_HEADERS(config.h)
|
||||||
AC_CONFIG_AUX_DIR(build-aux)
|
AC_CONFIG_AUX_DIR(build-aux)
|
||||||
AC_CONFIG_MACRO_DIR(build-aux)
|
AC_CONFIG_MACRO_DIR(build-aux)
|
||||||
|
|
||||||
|
AC_REQUIRE_AUX_FILE([tap-driver.sh])
|
||||||
|
|
||||||
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests silent-rules
|
AM_INIT_AUTOMAKE([foreign subdir-objects color-tests silent-rules
|
||||||
tar-pax no-dist-gzip dist-xz])
|
tar-pax no-dist-gzip dist-xz])
|
||||||
|
|
||||||
@ -29,6 +31,7 @@ AC_PROG_CC_GCOV
|
|||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
AC_PROG_MKDIR_P
|
AC_PROG_MKDIR_P
|
||||||
AC_PROG_LN_S
|
AC_PROG_LN_S
|
||||||
|
AC_PROG_AWK
|
||||||
|
|
||||||
AC_SYS_LARGEFILE
|
AC_SYS_LARGEFILE
|
||||||
|
|
||||||
@ -297,7 +300,7 @@ if (test "${enable_external_ell}" = "yes"); then
|
|||||||
test "${enable_monitor}" != "no" ||
|
test "${enable_monitor}" != "no" ||
|
||||||
test "${enable_wired}" = "yes" ||
|
test "${enable_wired}" = "yes" ||
|
||||||
test "${enable_hwsim}" = "yes"); then
|
test "${enable_hwsim}" = "yes"); then
|
||||||
ell_min_version="0.64"
|
ell_min_version="0.77"
|
||||||
else
|
else
|
||||||
ell_min_version="0.5"
|
ell_min_version="0.5"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -31,6 +31,12 @@ Methods array{dict} GetDiagnostics()
|
|||||||
|
|
||||||
TxMCS [optional] - Transmitting MCS index
|
TxMCS [optional] - Transmitting MCS index
|
||||||
|
|
||||||
|
InactiveTime [optional] - Time duration (in ms) for which the STA
|
||||||
|
connected to this BSS is currently inactive.
|
||||||
|
|
||||||
|
ConnectedTime [optional] - Time duration (in s) for which the STA
|
||||||
|
remains connected to this BSS.
|
||||||
|
|
||||||
Possible errors: net.connman.iwd.Failed
|
Possible errors: net.connman.iwd.Failed
|
||||||
net.connman.iwd.NotConnected
|
net.connman.iwd.NotConnected
|
||||||
net.connman.iwd.NotFound
|
net.connman.iwd.NotFound
|
||||||
|
|||||||
10
doc/basic-service-set.txt
Normal file
10
doc/basic-service-set.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
Basic service set hierarchy
|
||||||
|
=================
|
||||||
|
|
||||||
|
Service net.connman.iwd
|
||||||
|
Interface net.connman.iwd.BasicServiceSet
|
||||||
|
Object path /net/connman/iwd/{phy0,phy1,...}/{1,2,...}/Xxx
|
||||||
|
|
||||||
|
Properties string Address [readonly]
|
||||||
|
|
||||||
|
MAC address of BSS
|
||||||
@ -322,10 +322,10 @@ M18: Use appropriate logging levels
|
|||||||
An appropriate log level should be used depending on the type of message
|
An appropriate log level should be used depending on the type of message
|
||||||
being logged. Logging is done using the l_log APIs in ELL:
|
being logged. Logging is done using the l_log APIs in ELL:
|
||||||
|
|
||||||
l_error An unexpected condition ocurred. These are generally fatal to the
|
l_error An unexpected condition occurred. These are generally fatal to the
|
||||||
current connection/protocol that is running but not generally to IWD's
|
current connection/protocol that is running but not generally to IWD's
|
||||||
overall operation.
|
overall operation.
|
||||||
l_warn An unexpected, but non-fatal condition ocurred
|
l_warn An unexpected, but non-fatal condition occurred
|
||||||
l_notice Should not be used directly. This log level is reserved for special
|
l_notice Should not be used directly. This log level is reserved for special
|
||||||
event type notifications which is handled by iwd_notice().
|
event type notifications which is handled by iwd_notice().
|
||||||
l_info Information that is expected during normal operation. l_info's use
|
l_info Information that is expected during normal operation. l_info's use
|
||||||
|
|||||||
@ -135,7 +135,7 @@ Object path /net/connman/iwd/{phy0,phy1,...}/{1,2,...}
|
|||||||
void StartConfigurator(object agent_path)
|
void StartConfigurator(object agent_path)
|
||||||
|
|
||||||
Start a shared code configurator using an agent
|
Start a shared code configurator using an agent
|
||||||
(distingushed by 'agent_path') to obtain the shared
|
(distinguished by 'agent_path') to obtain the shared
|
||||||
code. This method is meant for an automated use case
|
code. This method is meant for an automated use case
|
||||||
where a configurator is capable of configuring multiple
|
where a configurator is capable of configuring multiple
|
||||||
enrollees, and distinguishing between them by their
|
enrollees, and distinguishing between them by their
|
||||||
@ -196,7 +196,7 @@ Methods void Release() [noreply]
|
|||||||
string RequestSharedCode(string identifier)
|
string RequestSharedCode(string identifier)
|
||||||
|
|
||||||
This method gets called when a shared code is requested
|
This method gets called when a shared code is requested
|
||||||
for a particular enrollee, distingushed by the
|
for a particular enrollee, distinguished by the
|
||||||
identifier. The shared code agent should lookup the
|
identifier. The shared code agent should lookup the
|
||||||
identifier and return the shared code, or return an
|
identifier and return the shared code, or return an
|
||||||
error if not found.
|
error if not found.
|
||||||
|
|||||||
@ -5,7 +5,7 @@ credentials for your e.g. cable/cellular provider, or via a dedicated account
|
|||||||
like Boingo. Lots of these services also allow you to roam between networks.
|
like Boingo. Lots of these services also allow you to roam between networks.
|
||||||
|
|
||||||
The underlying authentication is standard WPA2-Enterprise but Hotspot 2.0 adds a
|
The underlying authentication is standard WPA2-Enterprise but Hotspot 2.0 adds a
|
||||||
'discovery' stage to identifiying networks. This discovery is done using ANQP,
|
'discovery' stage to identifying networks. This discovery is done using ANQP,
|
||||||
which queries the network for additional information to determine if the client
|
which queries the network for additional information to determine if the client
|
||||||
has the credentials to connect.
|
has the credentials to connect.
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,12 @@ Methods void Connect()
|
|||||||
the object path to connect to specified network.
|
the object path to connect to specified network.
|
||||||
Connecting to WEP networks is not supported.
|
Connecting to WEP networks is not supported.
|
||||||
|
|
||||||
|
Note: When [General].EnableNetworkConfiguration is set
|
||||||
|
to true a call to Connect() has the potential to take
|
||||||
|
a significant amount of time. Specifically if DHCP is
|
||||||
|
either slow, or is unable to complete. The timeout for
|
||||||
|
DHCP is roughly 30 seconds per BSS.
|
||||||
|
|
||||||
Possible errors: net.connman.iwd.Aborted
|
Possible errors: net.connman.iwd.Aborted
|
||||||
net.connman.iwd.Busy
|
net.connman.iwd.Busy
|
||||||
net.connman.iwd.Failed
|
net.connman.iwd.Failed
|
||||||
@ -50,3 +56,8 @@ Properties string Name [readonly]
|
|||||||
corresponding to this Network. If the network
|
corresponding to this Network. If the network
|
||||||
is not provisioned or has not been connected to
|
is not provisioned or has not been connected to
|
||||||
before, the property is omitted.
|
before, the property is omitted.
|
||||||
|
|
||||||
|
array(object) ExtendedServiceSet [readonly]
|
||||||
|
|
||||||
|
Contains a list of paths of each individual
|
||||||
|
BasicServiceSet object.
|
||||||
|
|||||||
@ -56,7 +56,7 @@ Methods array(on) GetPeers()
|
|||||||
between requested threshold values is a compromise
|
between requested threshold values is a compromise
|
||||||
between resolution and the frequency of system
|
between resolution and the frequency of system
|
||||||
wakeups and context-switches that are going to be
|
wakeups and context-switches that are going to be
|
||||||
occuring to update the client's signal meter. Only
|
occurring to update the client's signal meter. Only
|
||||||
one agent can be registered at any time.
|
one agent can be registered at any time.
|
||||||
|
|
||||||
Possible errors: [service].Error.InvalidArguments
|
Possible errors: [service].Error.InvalidArguments
|
||||||
|
|||||||
@ -164,6 +164,29 @@ Properties string State [readonly]
|
|||||||
for networks. net.connman.iwd.Network objects are
|
for networks. net.connman.iwd.Network objects are
|
||||||
updated when this property goes from true to false.
|
updated when this property goes from true to false.
|
||||||
|
|
||||||
|
object ConnectedAccessPoint [readonly, optional]
|
||||||
|
|
||||||
|
net.connman.iwd.BasicServiceSet object representing the
|
||||||
|
BSS the device is currently connected to or to which
|
||||||
|
a connection is in progress.
|
||||||
|
|
||||||
|
ao Affinities [optional] [experimental]
|
||||||
|
|
||||||
|
Array of net.connman.iwd.BasicServiceSet object paths
|
||||||
|
that will be treated with higher affinity compared to
|
||||||
|
other BSS's. Currently the only allowed value to be
|
||||||
|
set in this array is the path to the currently connected
|
||||||
|
BasicServiceSet object, i.e.
|
||||||
|
Station.ConnectedAccessPoint.
|
||||||
|
|
||||||
|
Setting the affinity will lower the roaming threshold,
|
||||||
|
effectively locking IWD to the current BSS unless the
|
||||||
|
RSSI drops below the critical threshold set by
|
||||||
|
[General].CriticalRoamThreshold{5G} at which point
|
||||||
|
IWD will proceed with normal roaming behavior.
|
||||||
|
|
||||||
|
This property is cleared on roams/disconnections.
|
||||||
|
|
||||||
SignalLevelAgent hierarchy
|
SignalLevelAgent hierarchy
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
|
|||||||
@ -53,6 +53,12 @@ Methods dict GetDiagnostics()
|
|||||||
- GCMP-256
|
- GCMP-256
|
||||||
- CCMP-256
|
- CCMP-256
|
||||||
|
|
||||||
|
InactiveTime [optional] - Time duration (in ms) for which this STA
|
||||||
|
is currently inactive.
|
||||||
|
|
||||||
|
ConnectedTime [optional] - Time Duration (in s) for which this STA
|
||||||
|
remains connected to the BSS.
|
||||||
|
|
||||||
Possible errors: net.connman.iwd.Busy
|
Possible errors: net.connman.iwd.Busy
|
||||||
net.connman.iwd.Failed
|
net.connman.iwd.Failed
|
||||||
net.connman.iwd.NotConnected
|
net.connman.iwd.NotConnected
|
||||||
|
|||||||
@ -218,7 +218,7 @@ supplicant running IWD:
|
|||||||
#~~~~~~~~~~~~~~~~~~~~~~~~~ hw.conf ~~~~~~~~~~~~~~~~~~~~~~~~~
|
#~~~~~~~~~~~~~~~~~~~~~~~~~ hw.conf ~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
# Lines starting with # are ignored
|
# Lines starting with # are ignored
|
||||||
|
|
||||||
# 'SETUP' is a manditory configuration group.
|
# 'SETUP' is a mandatory configuration group.
|
||||||
[SETUP]
|
[SETUP]
|
||||||
#
|
#
|
||||||
# Total number of radios requested per network setup. This includes
|
# Total number of radios requested per network setup. This includes
|
||||||
|
|||||||
261
monitor/main.c
261
monitor/main.c
@ -224,129 +224,42 @@ struct iwmon_interface {
|
|||||||
char *ifname;
|
char *ifname;
|
||||||
bool exists;
|
bool exists;
|
||||||
struct l_netlink *rtnl;
|
struct l_netlink *rtnl;
|
||||||
struct l_netlink *genl;
|
struct l_genl *genl;
|
||||||
struct l_io *io;
|
struct l_io *io;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct iwmon_interface monitor_interface = { };
|
static struct iwmon_interface monitor_interface = { };
|
||||||
|
|
||||||
static void genl_parse(uint16_t type, const void *data, uint32_t len,
|
static void nl80211_appeared(const struct l_genl_family_info *info,
|
||||||
const char *ifname)
|
void *user_data)
|
||||||
{
|
{
|
||||||
const struct genlmsghdr *genlmsg = data;
|
const char *ifname = user_data;
|
||||||
const struct nlattr *nla;
|
|
||||||
char name[GENL_NAMSIZ];
|
|
||||||
uint16_t id = 0;
|
|
||||||
|
|
||||||
if (nlmon)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (type != GENL_ID_CTRL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (genlmsg->cmd != CTRL_CMD_NEWFAMILY)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (nla = data + GENL_HDRLEN; NLA_OK(nla, len);
|
|
||||||
nla = NLA_NEXT(nla, len)) {
|
|
||||||
switch (nla->nla_type & NLA_TYPE_MASK) {
|
|
||||||
case CTRL_ATTR_FAMILY_ID:
|
|
||||||
id = *((uint16_t *) NLA_DATA(nla));
|
|
||||||
break;
|
|
||||||
case CTRL_ATTR_FAMILY_NAME:
|
|
||||||
strncpy(name, NLA_DATA(nla), GENL_NAMSIZ - 1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (strcmp(name, NL80211_GENL_NAME))
|
|
||||||
return;
|
|
||||||
|
|
||||||
monitor_interface.io = open_packet(ifname);
|
monitor_interface.io = open_packet(ifname);
|
||||||
if (!monitor_interface.io)
|
if (!monitor_interface.io)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
nlmon = nlmon_open(id, writer_path, &config);
|
nlmon = nlmon_open(l_genl_family_info_get_id(info),
|
||||||
|
writer_path, &config);
|
||||||
if (!nlmon)
|
if (!nlmon)
|
||||||
goto failed;
|
goto failed;
|
||||||
|
|
||||||
l_io_set_read_handler(monitor_interface.io, nlmon_receive, nlmon, NULL);
|
l_io_set_read_handler(monitor_interface.io, nlmon_receive, nlmon, NULL);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
l_main_quit();
|
l_main_quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void genl_notify(uint16_t type, const void *data,
|
static struct l_genl *genl_lookup(const char *ifname)
|
||||||
uint32_t len, void *user_data)
|
|
||||||
{
|
{
|
||||||
const char *ifname = user_data;
|
struct l_genl *genl = l_genl_new();
|
||||||
|
|
||||||
genl_parse(type, data, len, ifname);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void genl_callback(int error, uint16_t type, const void *data,
|
|
||||||
uint32_t len, void *user_data)
|
|
||||||
{
|
|
||||||
const char *ifname = user_data;
|
|
||||||
|
|
||||||
if (error < 0) {
|
|
||||||
fprintf(stderr, "Failed to lookup nl80211 family\n");
|
|
||||||
l_main_quit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
genl_parse(type, data, len, ifname);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct l_netlink *genl_lookup(const char *ifname)
|
|
||||||
{
|
|
||||||
struct l_netlink *genl;
|
|
||||||
char buf[GENL_HDRLEN + NLA_HDRLEN + GENL_NAMSIZ];
|
|
||||||
struct genlmsghdr *genlmsg;
|
|
||||||
struct nlattr *nla;
|
|
||||||
|
|
||||||
genl = l_netlink_new(NETLINK_GENERIC);
|
|
||||||
|
|
||||||
l_netlink_register(genl, GENL_ID_CTRL, genl_notify, NULL, NULL);
|
|
||||||
|
|
||||||
genlmsg = (struct genlmsghdr *) buf;
|
|
||||||
genlmsg->cmd = CTRL_CMD_GETFAMILY;
|
|
||||||
genlmsg->version = 0;
|
|
||||||
genlmsg->reserved = 0;
|
|
||||||
|
|
||||||
nla = (struct nlattr *) (buf + GENL_HDRLEN);
|
|
||||||
nla->nla_len = NLA_HDRLEN + GENL_NAMSIZ;
|
|
||||||
nla->nla_type = CTRL_ATTR_FAMILY_NAME;
|
|
||||||
strncpy(buf + GENL_HDRLEN + NLA_HDRLEN,
|
|
||||||
NL80211_GENL_NAME, GENL_NAMSIZ);
|
|
||||||
|
|
||||||
l_netlink_send(genl, GENL_ID_CTRL, 0, buf, sizeof(buf),
|
|
||||||
genl_callback, (char *) ifname, NULL);
|
|
||||||
|
|
||||||
|
l_genl_request_family(genl, NL80211_GENL_NAME, nl80211_appeared,
|
||||||
|
(char *) ifname, NULL);
|
||||||
return genl;
|
return genl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t rta_add(void *rta_buf, unsigned short type, uint16_t len,
|
|
||||||
const void *data)
|
|
||||||
{
|
|
||||||
unsigned short rta_len = RTA_LENGTH(len);
|
|
||||||
struct rtattr *rta = rta_buf;
|
|
||||||
|
|
||||||
memset(RTA_DATA(rta), 0, RTA_SPACE(len));
|
|
||||||
|
|
||||||
rta->rta_len = rta_len;
|
|
||||||
rta->rta_type = type;
|
|
||||||
if (len)
|
|
||||||
memcpy(RTA_DATA(rta), data, len);
|
|
||||||
|
|
||||||
return RTA_SPACE(len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool rta_linkinfo_kind(struct rtattr *rta, unsigned short len,
|
static bool rta_linkinfo_kind(struct rtattr *rta, unsigned short len,
|
||||||
const char* kind)
|
const char* kind)
|
||||||
{
|
{
|
||||||
@ -375,10 +288,9 @@ static struct l_netlink *rtm_interface_send_message(struct l_netlink *rtnl,
|
|||||||
{
|
{
|
||||||
size_t nlmon_type_len = strlen(NLMON_TYPE);
|
size_t nlmon_type_len = strlen(NLMON_TYPE);
|
||||||
unsigned short ifname_len = 0;
|
unsigned short ifname_len = 0;
|
||||||
size_t bufsize;
|
struct l_netlink_message *nlm;
|
||||||
struct ifinfomsg *rtmmsg;
|
struct ifinfomsg ifi;
|
||||||
void *rta_buf;
|
uint16_t flags = 0;
|
||||||
struct rtattr *linkinfo_rta;
|
|
||||||
|
|
||||||
if (ifname) {
|
if (ifname) {
|
||||||
ifname_len = strlen(ifname) + 1;
|
ifname_len = strlen(ifname) + 1;
|
||||||
@ -387,64 +299,41 @@ static struct l_netlink *rtm_interface_send_message(struct l_netlink *rtnl,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!L_IN_SET(rtm_msg_type, RTM_NEWLINK, RTM_DELLINK, RTM_GETLINK))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (!rtnl)
|
if (!rtnl)
|
||||||
rtnl = l_netlink_new(NETLINK_ROUTE);
|
rtnl = l_netlink_new(NETLINK_ROUTE);
|
||||||
|
|
||||||
if (!rtnl)
|
if (!rtnl)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
bufsize = NLMSG_LENGTH(sizeof(struct ifinfomsg)) +
|
memset(&ifi, 0, sizeof(ifi));
|
||||||
RTA_SPACE(ifname_len) + RTA_SPACE(0) +
|
ifi.ifi_family = AF_UNSPEC;
|
||||||
RTA_SPACE(nlmon_type_len);
|
ifi.ifi_change = ~0;
|
||||||
|
|
||||||
rtmmsg = l_malloc(bufsize);
|
|
||||||
memset(rtmmsg, 0, bufsize);
|
|
||||||
|
|
||||||
rtmmsg->ifi_family = AF_UNSPEC;
|
|
||||||
rtmmsg->ifi_change = ~0;
|
|
||||||
|
|
||||||
rta_buf = rtmmsg + 1;
|
|
||||||
|
|
||||||
if (ifname)
|
|
||||||
rta_buf += rta_add(rta_buf, IFLA_IFNAME, ifname_len, ifname);
|
|
||||||
|
|
||||||
linkinfo_rta = rta_buf;
|
|
||||||
|
|
||||||
rta_buf += rta_add(rta_buf, IFLA_LINKINFO, 0, NULL);
|
|
||||||
rta_buf += rta_add(rta_buf, IFLA_INFO_KIND, nlmon_type_len, NLMON_TYPE);
|
|
||||||
|
|
||||||
linkinfo_rta->rta_len = rta_buf - (void *) linkinfo_rta;
|
|
||||||
|
|
||||||
switch (rtm_msg_type) {
|
switch (rtm_msg_type) {
|
||||||
case RTM_NEWLINK:
|
case RTM_NEWLINK:
|
||||||
rtmmsg->ifi_flags = IFF_UP | IFF_ALLMULTI | IFF_NOARP;
|
ifi.ifi_flags = IFF_UP | IFF_ALLMULTI | IFF_NOARP;
|
||||||
|
flags = NLM_F_CREATE | NLM_F_EXCL;
|
||||||
l_netlink_send(rtnl, RTM_NEWLINK, NLM_F_CREATE|NLM_F_EXCL,
|
|
||||||
rtmmsg, rta_buf - (void *) rtmmsg, callback,
|
|
||||||
user_data, destroy);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTM_DELLINK:
|
|
||||||
rta_buf += rta_add(rta_buf, IFLA_IFNAME, ifname_len, ifname);
|
|
||||||
|
|
||||||
l_netlink_send(rtnl, RTM_DELLINK, 0, rtmmsg,
|
|
||||||
rta_buf - (void *)rtmmsg, callback, user_data,
|
|
||||||
destroy);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RTM_GETLINK:
|
case RTM_GETLINK:
|
||||||
l_netlink_send(rtnl, RTM_GETLINK, NLM_F_DUMP, rtmmsg,
|
flags = NLM_F_DUMP;
|
||||||
rta_buf - (void *)rtmmsg, callback, user_data,
|
|
||||||
destroy);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
l_netlink_destroy(rtnl);
|
|
||||||
rtnl = NULL;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
l_free(rtmmsg);
|
nlm = l_netlink_message_new(rtm_msg_type, flags);;
|
||||||
|
l_netlink_message_add_header(nlm, &ifi, sizeof(ifi));
|
||||||
|
|
||||||
|
if (ifname)
|
||||||
|
l_netlink_message_append(nlm, IFLA_IFNAME, ifname, ifname_len);
|
||||||
|
|
||||||
|
l_netlink_message_enter_nested(nlm, IFLA_LINKINFO);
|
||||||
|
l_netlink_message_append(nlm, IFLA_INFO_KIND,
|
||||||
|
NLMON_TYPE, nlmon_type_len);
|
||||||
|
l_netlink_message_leave_nested(nlm);
|
||||||
|
|
||||||
|
l_netlink_send(rtnl, nlm, callback, user_data, destroy);
|
||||||
|
|
||||||
return rtnl;
|
return rtnl;
|
||||||
}
|
}
|
||||||
@ -689,7 +578,7 @@ static int analyze_pcap(const char *pathname)
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
printf(" Number of packets: %lu\n", pkt_count);
|
printf(" Number of packets: %lu\n", pkt_count);
|
||||||
printf(" Short packets: %lu\n", pkt_short);
|
printf(" Short packets: %lu\n", pkt_short);
|
||||||
printf(" Tuncated packets: %lu\n", pkt_trunc);
|
printf(" Truncated packets: %lu\n", pkt_trunc);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf(" Ethernet packets: %lu\n", pkt_ether);
|
printf(" Ethernet packets: %lu\n", pkt_ether);
|
||||||
printf(" PAE packets: %lu\n", pkt_pae);
|
printf(" PAE packets: %lu\n", pkt_pae);
|
||||||
@ -829,29 +718,36 @@ static void usage(void)
|
|||||||
"Usage:\n");
|
"Usage:\n");
|
||||||
printf("\tiwmon [options]\n");
|
printf("\tiwmon [options]\n");
|
||||||
printf("Options:\n"
|
printf("Options:\n"
|
||||||
"\t-r, --read <file> Read netlink PCAP trace file\n"
|
"\t-r, --read <file> Read netlink PCAP trace file\n"
|
||||||
"\t-w, --write <file> Write netlink PCAP trace file\n"
|
"\t-w, --write <file> Write netlink PCAP trace file\n"
|
||||||
"\t-a, --analyze <file> Analyze netlink PCAP trace file\n"
|
"\t-a, --analyze <file> Analyze netlink PCAP trace file\n"
|
||||||
"\t-i, --interface <dev> Use specified netlink monitor\n"
|
"\t-i, --interface <dev> Use specified netlink monitor\n"
|
||||||
"\t-n, --nortnl Don't show RTNL output\n"
|
"\t-n, --nortnl Don't show RTNL output\n"
|
||||||
"\t-y, --nowiphy Don't show 'New Wiphy' output\n"
|
"\t-y, --nowiphy Don't show 'New Wiphy' output\n"
|
||||||
"\t-s, --noscan Don't show scan result output\n"
|
"\t-s, --noscan Don't show scan result output\n"
|
||||||
"\t-e, --noies Don't show IEs except SSID\n"
|
"\t-e, --noies Don't show IEs except SSID\n"
|
||||||
"\t-h, --help Show help options\n");
|
"\t-t, --time-format <format> Time format to display. Either\n"
|
||||||
|
"\t\t\t\t 'delta' or 'utc'.\n"
|
||||||
|
"\t-W,--pcap-count Maximum number of PCAP files\n"
|
||||||
|
"\t-C,--pcap-size Maximum size (MB) of PCAP files\n"
|
||||||
|
"\t-h, --help Show help options\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct option main_options[] = {
|
static const struct option main_options[] = {
|
||||||
{ "read", required_argument, NULL, 'r' },
|
{ "read", required_argument, NULL, 'r' },
|
||||||
{ "write", required_argument, NULL, 'w' },
|
{ "write", required_argument, NULL, 'w' },
|
||||||
{ "analyze", required_argument, NULL, 'a' },
|
{ "analyze", required_argument, NULL, 'a' },
|
||||||
{ "nl80211", required_argument, NULL, 'F' },
|
{ "nl80211", required_argument, NULL, 'F' },
|
||||||
{ "interface", required_argument, NULL, 'i' },
|
{ "interface", required_argument, NULL, 'i' },
|
||||||
{ "nortnl", no_argument, NULL, 'n' },
|
{ "nortnl", no_argument, NULL, 'n' },
|
||||||
{ "nowiphy", no_argument, NULL, 'y' },
|
{ "nowiphy", no_argument, NULL, 'y' },
|
||||||
{ "noscan", no_argument, NULL, 's' },
|
{ "noscan", no_argument, NULL, 's' },
|
||||||
{ "noies", no_argument, NULL, 'e' },
|
{ "noies", no_argument, NULL, 'e' },
|
||||||
{ "version", no_argument, NULL, 'v' },
|
{ "time-format", required_argument, NULL, 't' },
|
||||||
{ "help", no_argument, NULL, 'h' },
|
{ "pcap-count", required_argument, NULL, 'W' },
|
||||||
|
{ "pcap-size", required_argument, NULL, 'C' },
|
||||||
|
{ "version", no_argument, NULL, 'v' },
|
||||||
|
{ "help", no_argument, NULL, 'h' },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -865,7 +761,7 @@ int main(int argc, char *argv[])
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
int opt;
|
int opt;
|
||||||
|
|
||||||
opt = getopt_long(argc, argv, "r:w:a:i:nvhyse",
|
opt = getopt_long(argc, argv, "r:w:a:i:t:W:C:nvhyse",
|
||||||
main_options, NULL);
|
main_options, NULL);
|
||||||
if (opt < 0)
|
if (opt < 0)
|
||||||
break;
|
break;
|
||||||
@ -895,6 +791,35 @@ int main(int argc, char *argv[])
|
|||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
config.noies = true;
|
config.noies = true;
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
if (!strcmp(optarg, "delta"))
|
||||||
|
config.time_format = TIME_FORMAT_DELTA;
|
||||||
|
else if (!strcmp(optarg, "utc"))
|
||||||
|
config.time_format = TIME_FORMAT_UTC;
|
||||||
|
else {
|
||||||
|
printf("Invalid time format '%s'", optarg);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'W':
|
||||||
|
if (l_safe_atou32(optarg,
|
||||||
|
&config.pcap_file_count) < 0 ||
|
||||||
|
config.pcap_file_count == 0) {
|
||||||
|
printf("Invalid file count '%s'\n", optarg);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'C':
|
||||||
|
if (l_safe_atou32(optarg,
|
||||||
|
&config.pcap_file_size) < 0 ||
|
||||||
|
config.pcap_file_size == 0) {
|
||||||
|
printf("Invalid file size '%s'\n", optarg);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
printf("%s\n", VERSION);
|
printf("%s\n", VERSION);
|
||||||
@ -957,7 +882,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
l_io_destroy(monitor_interface.io);
|
l_io_destroy(monitor_interface.io);
|
||||||
l_netlink_destroy(monitor_interface.rtnl);
|
l_netlink_destroy(monitor_interface.rtnl);
|
||||||
l_netlink_destroy(monitor_interface.genl);
|
l_genl_unref(monitor_interface.genl);
|
||||||
l_free(monitor_interface.ifname);
|
l_free(monitor_interface.ifname);
|
||||||
|
|
||||||
nlmon_close(nlmon);
|
nlmon_close(nlmon);
|
||||||
|
|||||||
324
monitor/nlmon.c
324
monitor/nlmon.c
@ -29,6 +29,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <time.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
@ -37,16 +38,26 @@
|
|||||||
#include <linux/if.h>
|
#include <linux/if.h>
|
||||||
#include <linux/if_packet.h>
|
#include <linux/if_packet.h>
|
||||||
#include <linux/if_ether.h>
|
#include <linux/if_ether.h>
|
||||||
|
#include <linux/if_link.h>
|
||||||
#include <linux/netlink.h>
|
#include <linux/netlink.h>
|
||||||
#include <linux/genetlink.h>
|
#include <linux/genetlink.h>
|
||||||
#include <linux/rtnetlink.h>
|
#include <linux/rtnetlink.h>
|
||||||
#include <linux/filter.h>
|
#include <linux/filter.h>
|
||||||
|
#include <linux/limits.h>
|
||||||
#include <ell/ell.h>
|
#include <ell/ell.h>
|
||||||
|
|
||||||
#ifndef ARPHRD_NETLINK
|
#ifndef ARPHRD_NETLINK
|
||||||
#define ARPHRD_NETLINK 824
|
#define ARPHRD_NETLINK 824
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef RMNET_FLAGS_INGRESS_MAP_CKSUMV5
|
||||||
|
#define RMNET_FLAGS_INGRESS_MAP_CKSUMV5 (1U << 4)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RMNET_FLAGS_EGRESS_MAP_CKSUMV5
|
||||||
|
#define RMNET_FLAGS_EGRESS_MAP_CKSUMV5 (1U << 5)
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "linux/nl80211.h"
|
#include "linux/nl80211.h"
|
||||||
|
|
||||||
#include "ell/useful.h"
|
#include "ell/useful.h"
|
||||||
@ -84,6 +95,8 @@
|
|||||||
#define BSS_CAPABILITY_APSD (1<<11)
|
#define BSS_CAPABILITY_APSD (1<<11)
|
||||||
#define BSS_CAPABILITY_DSSS_OFDM (1<<13)
|
#define BSS_CAPABILITY_DSSS_OFDM (1<<13)
|
||||||
|
|
||||||
|
#define BYTES_PER_MB 1000000
|
||||||
|
|
||||||
struct nlmon *cur_nlmon;
|
struct nlmon *cur_nlmon;
|
||||||
|
|
||||||
enum msg_type {
|
enum msg_type {
|
||||||
@ -104,6 +117,12 @@ struct nlmon {
|
|||||||
bool noscan;
|
bool noscan;
|
||||||
bool noies;
|
bool noies;
|
||||||
bool read;
|
bool read;
|
||||||
|
enum time_format time_format;
|
||||||
|
|
||||||
|
char *file_prefix;
|
||||||
|
unsigned int file_idx;
|
||||||
|
unsigned int max_files;
|
||||||
|
unsigned int max_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nlmon_req {
|
struct nlmon_req {
|
||||||
@ -176,11 +195,15 @@ static void nlmon_req_free(void *data)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static time_t time_offset = ((time_t) -1);
|
static time_t time_offset = ((time_t) -1);
|
||||||
|
static enum time_format time_format;
|
||||||
|
|
||||||
static inline void update_time_offset(const struct timeval *tv)
|
static inline void update_time_offset(const struct timeval *tv,
|
||||||
|
enum time_format tf)
|
||||||
{
|
{
|
||||||
if (tv && time_offset == ((time_t) -1))
|
if (tv && time_offset == ((time_t) -1)) {
|
||||||
time_offset = tv->tv_sec;
|
time_offset = tv->tv_sec;
|
||||||
|
time_format = tf;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define print_indent(indent, color1, prefix, title, color2, fmt, args...) \
|
#define print_indent(indent, color1, prefix, title, color2, fmt, args...) \
|
||||||
@ -216,15 +239,38 @@ static void print_packet(const struct timeval *tv, char ident,
|
|||||||
int n, ts_len = 0, ts_pos = 0, len = 0, pos = 0;
|
int n, ts_len = 0, ts_pos = 0, len = 0, pos = 0;
|
||||||
|
|
||||||
if (tv) {
|
if (tv) {
|
||||||
|
struct tm *tm;
|
||||||
|
|
||||||
if (use_color()) {
|
if (use_color()) {
|
||||||
n = sprintf(ts_str + ts_pos, "%s", COLOR_TIMESTAMP);
|
n = sprintf(ts_str + ts_pos, "%s", COLOR_TIMESTAMP);
|
||||||
if (n > 0)
|
if (n > 0)
|
||||||
ts_pos += n;
|
ts_pos += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = sprintf(ts_str + ts_pos, " %" PRId64 ".%06" PRId64,
|
switch (time_format) {
|
||||||
|
case TIME_FORMAT_DELTA:
|
||||||
|
n = sprintf(ts_str + ts_pos, " %" PRId64 ".%06" PRId64,
|
||||||
(int64_t)tv->tv_sec - time_offset,
|
(int64_t)tv->tv_sec - time_offset,
|
||||||
(int64_t)tv->tv_usec);
|
(int64_t)tv->tv_usec);
|
||||||
|
break;
|
||||||
|
case TIME_FORMAT_UTC:
|
||||||
|
tm = gmtime(&tv->tv_sec);
|
||||||
|
if (!tm) {
|
||||||
|
n = sprintf(ts_str + ts_pos, "%s",
|
||||||
|
"Time error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = strftime(ts_str + ts_pos, sizeof(ts_str) - ts_pos,
|
||||||
|
"%b %d %H:%M:%S", tm);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Should never happen */
|
||||||
|
printf("Unknown time format");
|
||||||
|
l_main_quit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
ts_pos += n;
|
ts_pos += n;
|
||||||
ts_len += n;
|
ts_len += n;
|
||||||
@ -358,6 +404,7 @@ static const struct {
|
|||||||
{ { 0x00, 0x50, 0xf2 }, "Microsoft" },
|
{ { 0x00, 0x50, 0xf2 }, "Microsoft" },
|
||||||
{ { 0x00, 0x90, 0x4c }, "Epigram" },
|
{ { 0x00, 0x90, 0x4c }, "Epigram" },
|
||||||
{ { 0x50, 0x6f, 0x9a }, "Wi-Fi Alliance" },
|
{ { 0x50, 0x6f, 0x9a }, "Wi-Fi Alliance" },
|
||||||
|
{ { 0x00, 0x18, 0x0a }, "Cisco Meraki" },
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -482,7 +529,30 @@ static void print_ie_country(unsigned int level, const char *label,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_attr(level, "%s: %c%c%c", label, code[0], code[1], code[2]);
|
print_attr(level, "%s: %c%c", label, code[0], code[1]);
|
||||||
|
|
||||||
|
switch (code[2]) {
|
||||||
|
case ' ':
|
||||||
|
print_attr(level + 1,
|
||||||
|
"3rd octet: 0x%02x: All environments", code[2]);
|
||||||
|
break;
|
||||||
|
case 'O':
|
||||||
|
print_attr(level + 1,
|
||||||
|
"3rd octet: 0x%02x: Outdoor environments", code[2]);
|
||||||
|
break;
|
||||||
|
case 'I':
|
||||||
|
print_attr(level + 1,
|
||||||
|
"3rd octet: 0x%02x: Indoor environments", code[2]);
|
||||||
|
break;
|
||||||
|
case 'X':
|
||||||
|
print_attr(level + 1,
|
||||||
|
"3rd octet: 0x%02x: Non-country entity", code[2]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
print_attr(level + 1,
|
||||||
|
"3rd octet: 0x%02x: Annex E table", code[2]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
while (i < size) {
|
while (i < size) {
|
||||||
if (code[i] > 200) {
|
if (code[i] > 200) {
|
||||||
@ -1649,7 +1719,7 @@ static void print_ie_vht_capabilities(unsigned int level,
|
|||||||
[21] = "TXOP PS",
|
[21] = "TXOP PS",
|
||||||
[22] = "+HTC-VHT Capable",
|
[22] = "+HTC-VHT Capable",
|
||||||
[23 ... 25] = "Maximum A-MPDU Length Exponent",
|
[23 ... 25] = "Maximum A-MPDU Length Exponent",
|
||||||
[26 ... 27] = "VHT Link Adapation Capable",
|
[26 ... 27] = "VHT Link Adaptation Capable",
|
||||||
[28] = "RX Antenna Pattern Consistency",
|
[28] = "RX Antenna Pattern Consistency",
|
||||||
[29] = "TX Antenna Pattern Consistency",
|
[29] = "TX Antenna Pattern Consistency",
|
||||||
[30 ... 31] = "Extended NSS BW Support",
|
[30 ... 31] = "Extended NSS BW Support",
|
||||||
@ -1846,7 +1916,7 @@ static void print_ie_interworking(unsigned int level,
|
|||||||
size--;
|
size--;
|
||||||
ptr++;
|
ptr++;
|
||||||
|
|
||||||
if (!size)
|
if (size < 2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2452,6 +2522,86 @@ static void print_reduced_neighbor_report(unsigned int level, const char *label,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_neighbor_report(unsigned int level, const char *label,
|
||||||
|
const void *data, uint16_t size)
|
||||||
|
{
|
||||||
|
struct ie_tlv_iter iter;
|
||||||
|
struct ie_neighbor_report_info info;
|
||||||
|
|
||||||
|
const char *phy_type_table[] = {
|
||||||
|
[0] = NULL,
|
||||||
|
[1] = NULL,
|
||||||
|
[2] = "DSSS",
|
||||||
|
[3] = NULL,
|
||||||
|
[4] = "OFDM",
|
||||||
|
[5] = "HDRSSS",
|
||||||
|
[6] = "ERP",
|
||||||
|
[7] = "HT",
|
||||||
|
[8] = "DMG",
|
||||||
|
[9] = "VHT",
|
||||||
|
[10] = "TVHT",
|
||||||
|
[11] = "S1G",
|
||||||
|
[12] = "CDMG",
|
||||||
|
[13] = "CMMG",
|
||||||
|
[14] = "HE"
|
||||||
|
};
|
||||||
|
|
||||||
|
ie_tlv_iter_init(&iter, data - 2, size + 2);
|
||||||
|
|
||||||
|
if (!ie_tlv_iter_next(&iter))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ie_parse_neighbor_report(&iter, &info) < 0) {
|
||||||
|
print_attr(level, "Invalid Neighbor report");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_attr(level, "Neighbor Report for "MAC, MAC_STR(info.addr));
|
||||||
|
print_attr(level + 1, "Operating Class: %u", info.oper_class);
|
||||||
|
print_attr(level + 1, "Channel Number: %u", info.channel_num);
|
||||||
|
|
||||||
|
if (info.phy_type <= 14 && phy_type_table[info.phy_type])
|
||||||
|
print_attr(level + 1, "Phy Type: %s",
|
||||||
|
phy_type_table[info.phy_type]);
|
||||||
|
else
|
||||||
|
print_attr(level + 1, "Phy Type: Unknown (%u)", info.phy_type);
|
||||||
|
|
||||||
|
if (info.bss_transition_pref_present)
|
||||||
|
print_attr(level + 1, "BSS Transition Preference: %u",
|
||||||
|
info.bss_transition_pref);
|
||||||
|
|
||||||
|
switch (info.reachable) {
|
||||||
|
case 1:
|
||||||
|
print_attr(level + 1, "Reachability: Not Reachable");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
print_attr(level + 1, "Reachability: Unknown");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
print_attr(level + 1, "Reachability: Reachable");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_attr(level + 1, "BSSID Information");
|
||||||
|
|
||||||
|
if (info.security)
|
||||||
|
print_attr(level + 2, "Security bit set");
|
||||||
|
if (info.key_scope)
|
||||||
|
print_attr(level + 2, "Key scope bit set");
|
||||||
|
if (info.spectrum_mgmt)
|
||||||
|
print_attr(level + 2, "Spectrum Mgmt bit set");
|
||||||
|
if (info.qos)
|
||||||
|
print_attr(level + 2, "QoS bit set");
|
||||||
|
if (info.apsd)
|
||||||
|
print_attr(level + 2, "APSD bit set");
|
||||||
|
if (info.md)
|
||||||
|
print_attr(level + 2, "MD bit set");
|
||||||
|
if (info.ht)
|
||||||
|
print_attr(level + 2, "HT bit set");
|
||||||
|
}
|
||||||
|
|
||||||
static struct attr_entry ie_entry[] = {
|
static struct attr_entry ie_entry[] = {
|
||||||
{ IE_TYPE_SSID, "SSID",
|
{ IE_TYPE_SSID, "SSID",
|
||||||
ATTR_CUSTOM, { .function = print_ie_ssid } },
|
ATTR_CUSTOM, { .function = print_ie_ssid } },
|
||||||
@ -2520,6 +2670,8 @@ static struct attr_entry ie_entry[] = {
|
|||||||
ATTR_CUSTOM, { .function = print_reduced_neighbor_report } },
|
ATTR_CUSTOM, { .function = print_reduced_neighbor_report } },
|
||||||
{ IE_TYPE_RSNX, "RSNX",
|
{ IE_TYPE_RSNX, "RSNX",
|
||||||
ATTR_CUSTOM, { .function = print_rsnx } },
|
ATTR_CUSTOM, { .function = print_rsnx } },
|
||||||
|
{ IE_TYPE_NEIGHBOR_REPORT, "Neighbor Report",
|
||||||
|
ATTR_CUSTOM, { .function = print_neighbor_report } },
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -4979,6 +5131,7 @@ static void print_rm_action_frame(unsigned int level, const uint8_t *body,
|
|||||||
print_rm_request(level + 1, body + 1, body_len - 1);
|
print_rm_request(level + 1, body + 1, body_len - 1);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
|
case 5:
|
||||||
print_rm_report(level + 1, body + 1, body_len - 1);
|
print_rm_report(level + 1, body + 1, body_len - 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -5535,8 +5688,26 @@ static void print_cqm_event(unsigned int level, const char *label,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_cqm_thresholds(unsigned int level, const char *label,
|
||||||
|
const void *data, uint16_t size)
|
||||||
|
{
|
||||||
|
const int32_t *thresholds = data;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if (size % 4) {
|
||||||
|
printf("malformed packet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
print_attr(level, "%s:", label);
|
||||||
|
|
||||||
|
for (i = 0; i < size / 4; i++)
|
||||||
|
print_attr(level + 1, "Threshold: %d", thresholds[i]);
|
||||||
|
|
||||||
|
}
|
||||||
static const struct attr_entry cqm_table[] = {
|
static const struct attr_entry cqm_table[] = {
|
||||||
{ NL80211_ATTR_CQM_RSSI_THOLD, "RSSI threshold", ATTR_U32 },
|
{ NL80211_ATTR_CQM_RSSI_THOLD, "RSSI thresholds", ATTR_CUSTOM,
|
||||||
|
{ .function = print_cqm_thresholds } },
|
||||||
{ NL80211_ATTR_CQM_RSSI_HYST, "RSSI hysteresis", ATTR_U32 },
|
{ NL80211_ATTR_CQM_RSSI_HYST, "RSSI hysteresis", ATTR_U32 },
|
||||||
{ NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
|
{ NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT,
|
||||||
"RSSI threshold event", ATTR_CUSTOM,
|
"RSSI threshold event", ATTR_CUSTOM,
|
||||||
@ -7153,8 +7324,10 @@ static void print_message(struct nlmon *nlmon, const struct timeval *tv,
|
|||||||
if (nlmon->nowiphy && (cmd == NL80211_CMD_NEW_WIPHY))
|
if (nlmon->nowiphy && (cmd == NL80211_CMD_NEW_WIPHY))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (nlmon->noscan && ((cmd == NL80211_CMD_NEW_SCAN_RESULTS) ||
|
if (nlmon->noscan && L_IN_SET(cmd, NL80211_CMD_NEW_SCAN_RESULTS,
|
||||||
(cmd == NL80211_CMD_TRIGGER_SCAN)))
|
NL80211_CMD_NEW_SURVEY_RESULTS,
|
||||||
|
NL80211_CMD_TRIGGER_SCAN,
|
||||||
|
NL80211_CMD_GET_SURVEY))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -7229,6 +7402,64 @@ static bool nlmon_req_match(const void *a, const void *b)
|
|||||||
return (req->seq == match->seq && req->pid == match->pid);
|
return (req->seq == match->seq && req->pid == match->pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensures that PCAP names are zero padded when needed. This makes the files
|
||||||
|
* sort correctly.
|
||||||
|
*/
|
||||||
|
static void next_pcap_name(char *buf, size_t size, const char *prefix,
|
||||||
|
unsigned int idx, unsigned int max)
|
||||||
|
{
|
||||||
|
unsigned int ndigits = 1;
|
||||||
|
|
||||||
|
while (max > 9) {
|
||||||
|
max /= 10;
|
||||||
|
ndigits++;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buf, size, "%s%.*u", prefix, ndigits, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool check_pcap(struct nlmon *nlmon, size_t next_size)
|
||||||
|
{
|
||||||
|
char path[PATH_MAX];
|
||||||
|
|
||||||
|
if (!nlmon->pcap)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!nlmon->max_size)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (pcap_get_size(nlmon->pcap) + next_size <= nlmon->max_size)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
pcap_close(nlmon->pcap);
|
||||||
|
|
||||||
|
/* Exhausted the single PCAP file */
|
||||||
|
if (nlmon->max_files < 2) {
|
||||||
|
printf("Reached maximum size of PCAP, exiting\n");
|
||||||
|
nlmon->pcap = NULL;
|
||||||
|
l_main_quit();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
next_pcap_name(path, sizeof(path), nlmon->file_prefix,
|
||||||
|
++nlmon->file_idx, nlmon->max_files);
|
||||||
|
|
||||||
|
nlmon->pcap = pcap_create(path);
|
||||||
|
|
||||||
|
if (nlmon->max_files > nlmon->file_idx)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* Remove oldest PCAP file */
|
||||||
|
next_pcap_name(path, sizeof(path), nlmon->file_prefix,
|
||||||
|
nlmon->file_idx - nlmon->max_files, nlmon->max_files);
|
||||||
|
|
||||||
|
if (remove(path) < 0)
|
||||||
|
printf("Failed to remove old PCAP file %s\n", path);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static void store_packet(struct nlmon *nlmon, const struct timeval *tv,
|
static void store_packet(struct nlmon *nlmon, const struct timeval *tv,
|
||||||
uint16_t pkt_type,
|
uint16_t pkt_type,
|
||||||
uint16_t arphrd_type,
|
uint16_t arphrd_type,
|
||||||
@ -7237,7 +7468,7 @@ static void store_packet(struct nlmon *nlmon, const struct timeval *tv,
|
|||||||
{
|
{
|
||||||
uint8_t sll_hdr[16], *buf = sll_hdr;
|
uint8_t sll_hdr[16], *buf = sll_hdr;
|
||||||
|
|
||||||
if (!nlmon->pcap)
|
if (!check_pcap(nlmon, sizeof(sll_hdr) + size))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
memset(sll_hdr, 0, sizeof(sll_hdr));
|
memset(sll_hdr, 0, sizeof(sll_hdr));
|
||||||
@ -7362,6 +7593,10 @@ struct nlmon *nlmon_create(uint16_t id, const struct nlmon_config *config)
|
|||||||
nlmon->noscan = config->noscan;
|
nlmon->noscan = config->noscan;
|
||||||
nlmon->noies = config->noies;
|
nlmon->noies = config->noies;
|
||||||
nlmon->read = config->read_only;
|
nlmon->read = config->read_only;
|
||||||
|
nlmon->time_format = config->time_format;
|
||||||
|
nlmon->max_files = config->pcap_file_count;
|
||||||
|
/* Command line expects MB, but use bytes internally */
|
||||||
|
nlmon->max_size = config->pcap_file_size * BYTES_PER_MB;
|
||||||
|
|
||||||
return nlmon;
|
return nlmon;
|
||||||
}
|
}
|
||||||
@ -7496,8 +7731,51 @@ static void flags_str(const struct flag_names *table,
|
|||||||
pos += sprintf(str + pos, "]");
|
pos += sprintf(str + pos, "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_rmnet_flags(unsigned int indent,
|
||||||
|
const char *label, uint32_t flags)
|
||||||
|
{
|
||||||
|
if (flags & RMNET_FLAGS_INGRESS_DEAGGREGATION)
|
||||||
|
print_attr(indent, "%s: %s", label, "deaggregation");
|
||||||
|
if (flags & RMNET_FLAGS_INGRESS_MAP_COMMANDS)
|
||||||
|
print_attr(indent, "%s: %s", label, "map commands");
|
||||||
|
if (flags & RMNET_FLAGS_INGRESS_MAP_CKSUMV4)
|
||||||
|
print_attr(indent, "%s: %s", label, "ingress_mapv4");
|
||||||
|
if (flags & RMNET_FLAGS_EGRESS_MAP_CKSUMV4)
|
||||||
|
print_attr(indent, "%s: %s", label, "egress_mapv4");
|
||||||
|
if (flags & RMNET_FLAGS_INGRESS_MAP_CKSUMV5)
|
||||||
|
print_attr(indent, "%s: %s", label, "ingress_mapv5");
|
||||||
|
if (flags & RMNET_FLAGS_EGRESS_MAP_CKSUMV5)
|
||||||
|
print_attr(indent, "%s: %s", label, "egress_mapv5");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_ifla_rmnet_flags(unsigned int indent, const char *str,
|
||||||
|
const void *buf, uint16_t size)
|
||||||
|
{
|
||||||
|
struct ifla_rmnet_flags flags;
|
||||||
|
|
||||||
|
if (size != 8) {
|
||||||
|
printf("malformed packet\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&flags, buf, size);
|
||||||
|
|
||||||
|
print_attr(indent, "%s:", str);
|
||||||
|
print_rmnet_flags(indent + 1, "Flags", flags.flags);
|
||||||
|
print_rmnet_flags(indent + 1, "Mask", flags.mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct attr_entry link_info_data_entry[] = {
|
||||||
|
{ IFLA_RMNET_MUX_ID, "RMNet Mux Id", ATTR_U16 },
|
||||||
|
{ IFLA_RMNET_FLAGS, "RMNet Flags", ATTR_CUSTOM,
|
||||||
|
{ .function = print_ifla_rmnet_flags } },
|
||||||
|
{ },
|
||||||
|
};
|
||||||
|
|
||||||
static struct attr_entry link_info_entry[] = {
|
static struct attr_entry link_info_entry[] = {
|
||||||
{ IFLA_INFO_KIND, "Kind", ATTR_STRING },
|
{ IFLA_INFO_KIND, "Kind", ATTR_STRING },
|
||||||
|
{ IFLA_INFO_DATA, "Info Data",
|
||||||
|
ATTR_NESTED, { link_info_data_entry } },
|
||||||
{ },
|
{ },
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -7654,7 +7932,7 @@ static void print_rtnl_attributes(int indent, const struct attr_entry *table,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
for (attr = rt_attr; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
|
for (attr = rt_attr; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
|
||||||
uint16_t rta_type = attr->rta_type;
|
uint16_t rta_type = attr->rta_type & NLA_TYPE_MASK;
|
||||||
enum attr_type type = ATTR_UNSPEC;
|
enum attr_type type = ATTR_UNSPEC;
|
||||||
attr_func_t function;
|
attr_func_t function;
|
||||||
const struct attr_entry *nested;
|
const struct attr_entry *nested;
|
||||||
@ -8155,7 +8433,10 @@ void nlmon_print_rtnl(struct nlmon *nlmon, const struct timeval *tv,
|
|||||||
int64_t aligned_size = NLMSG_ALIGN(size);
|
int64_t aligned_size = NLMSG_ALIGN(size);
|
||||||
const struct nlmsghdr *nlmsg;
|
const struct nlmsghdr *nlmsg;
|
||||||
|
|
||||||
update_time_offset(tv);
|
if (nlmon->nortnl)
|
||||||
|
return;
|
||||||
|
|
||||||
|
update_time_offset(tv, nlmon->time_format);
|
||||||
|
|
||||||
for (nlmsg = data; NLMSG_OK(nlmsg, aligned_size);
|
for (nlmsg = data; NLMSG_OK(nlmsg, aligned_size);
|
||||||
nlmsg = NLMSG_NEXT(nlmsg, aligned_size)) {
|
nlmsg = NLMSG_NEXT(nlmsg, aligned_size)) {
|
||||||
@ -8193,7 +8474,7 @@ void nlmon_print_genl(struct nlmon *nlmon, const struct timeval *tv,
|
|||||||
{
|
{
|
||||||
const struct nlmsghdr *nlmsg;
|
const struct nlmsghdr *nlmsg;
|
||||||
|
|
||||||
update_time_offset(tv);
|
update_time_offset(tv, nlmon->time_format);
|
||||||
|
|
||||||
for (nlmsg = data; NLMSG_OK(nlmsg, size);
|
for (nlmsg = data; NLMSG_OK(nlmsg, size);
|
||||||
nlmsg = NLMSG_NEXT(nlmsg, size)) {
|
nlmsg = NLMSG_NEXT(nlmsg, size)) {
|
||||||
@ -8202,7 +8483,8 @@ void nlmon_print_genl(struct nlmon *nlmon, const struct timeval *tv,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!nlmon->read && nlmsg->nlmsg_type != nlmon->id)
|
if (nlmsg->nlmsg_type >= NLMSG_MIN_TYPE && !nlmon->read &&
|
||||||
|
nlmsg->nlmsg_type != nlmon->id)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
nlmon_message(nlmon, tv, nlmsg);
|
nlmon_message(nlmon, tv, nlmsg);
|
||||||
@ -8215,7 +8497,7 @@ void nlmon_print_pae(struct nlmon *nlmon, const struct timeval *tv,
|
|||||||
{
|
{
|
||||||
char extra_str[16];
|
char extra_str[16];
|
||||||
|
|
||||||
update_time_offset(tv);
|
update_time_offset(tv, nlmon->time_format);
|
||||||
|
|
||||||
sprintf(extra_str, "len %u", size);
|
sprintf(extra_str, "len %u", size);
|
||||||
|
|
||||||
@ -8342,13 +8624,20 @@ struct nlmon *nlmon_open(uint16_t id, const char *pathname,
|
|||||||
struct nlmon *nlmon;
|
struct nlmon *nlmon;
|
||||||
struct l_io *pae_io;
|
struct l_io *pae_io;
|
||||||
struct pcap *pcap;
|
struct pcap *pcap;
|
||||||
|
char path[PATH_MAX];
|
||||||
|
|
||||||
pae_io = open_pae();
|
pae_io = open_pae();
|
||||||
if (!pae_io)
|
if (!pae_io)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (pathname) {
|
if (pathname) {
|
||||||
pcap = pcap_create(pathname);
|
if (config->pcap_file_count > 1)
|
||||||
|
next_pcap_name(path, sizeof(path), pathname,
|
||||||
|
0, config->pcap_file_count);
|
||||||
|
else
|
||||||
|
snprintf(path, sizeof(path), "%s", pathname);
|
||||||
|
|
||||||
|
pcap = pcap_create(path);
|
||||||
if (!pcap) {
|
if (!pcap) {
|
||||||
l_io_destroy(pae_io);
|
l_io_destroy(pae_io);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -8361,6 +8650,7 @@ struct nlmon *nlmon_open(uint16_t id, const char *pathname,
|
|||||||
|
|
||||||
nlmon->pae_io = pae_io;
|
nlmon->pae_io = pae_io;
|
||||||
nlmon->pcap = pcap;
|
nlmon->pcap = pcap;
|
||||||
|
nlmon->file_prefix = l_strdup(pathname);
|
||||||
|
|
||||||
l_io_set_read_handler(nlmon->pae_io, pae_receive, nlmon, NULL);
|
l_io_set_read_handler(nlmon->pae_io, pae_receive, nlmon, NULL);
|
||||||
|
|
||||||
@ -8383,5 +8673,7 @@ void nlmon_close(struct nlmon *nlmon)
|
|||||||
if (nlmon->pcap)
|
if (nlmon->pcap)
|
||||||
pcap_close(nlmon->pcap);
|
pcap_close(nlmon->pcap);
|
||||||
|
|
||||||
|
l_free(nlmon->file_prefix);
|
||||||
|
|
||||||
l_free(nlmon);
|
l_free(nlmon);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,12 +25,22 @@
|
|||||||
|
|
||||||
struct nlmon;
|
struct nlmon;
|
||||||
|
|
||||||
|
enum time_format {
|
||||||
|
TIME_FORMAT_DELTA,
|
||||||
|
TIME_FORMAT_UTC,
|
||||||
|
};
|
||||||
|
|
||||||
struct nlmon_config {
|
struct nlmon_config {
|
||||||
bool nortnl;
|
bool nortnl;
|
||||||
bool nowiphy;
|
bool nowiphy;
|
||||||
bool noscan;
|
bool noscan;
|
||||||
bool noies;
|
bool noies;
|
||||||
bool read_only;
|
bool read_only;
|
||||||
|
enum time_format time_format;
|
||||||
|
|
||||||
|
/* File size in MB */
|
||||||
|
uint32_t pcap_file_size;
|
||||||
|
uint32_t pcap_file_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nlmon *nlmon_open(uint16_t id, const char *pathname,
|
struct nlmon *nlmon_open(uint16_t id, const char *pathname,
|
||||||
|
|||||||
@ -60,6 +60,7 @@ struct pcap {
|
|||||||
bool closed;
|
bool closed;
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
uint32_t snaplen;
|
uint32_t snaplen;
|
||||||
|
size_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct pcap *pcap_open(const char *pathname)
|
struct pcap *pcap_open(const char *pathname)
|
||||||
@ -152,6 +153,8 @@ struct pcap *pcap_create(const char *pathname)
|
|||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pcap->size += len;
|
||||||
|
|
||||||
return pcap;
|
return pcap;
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
@ -188,6 +191,11 @@ uint32_t pcap_get_snaplen(struct pcap *pcap)
|
|||||||
return pcap->snaplen;
|
return pcap->snaplen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t pcap_get_size(struct pcap *pcap)
|
||||||
|
{
|
||||||
|
return pcap->size;
|
||||||
|
}
|
||||||
|
|
||||||
bool pcap_read(struct pcap *pcap, struct timeval *tv,
|
bool pcap_read(struct pcap *pcap, struct timeval *tv,
|
||||||
void *data, uint32_t size, uint32_t *len, uint32_t *real_len)
|
void *data, uint32_t size, uint32_t *len, uint32_t *real_len)
|
||||||
{
|
{
|
||||||
@ -279,5 +287,7 @@ bool pcap_write(struct pcap *pcap, const struct timeval *tv,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pcap->size += written;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,6 +36,7 @@ void pcap_close(struct pcap *pcap);
|
|||||||
|
|
||||||
uint32_t pcap_get_type(struct pcap *pcap);
|
uint32_t pcap_get_type(struct pcap *pcap);
|
||||||
uint32_t pcap_get_snaplen(struct pcap *pcap);
|
uint32_t pcap_get_snaplen(struct pcap *pcap);
|
||||||
|
size_t pcap_get_size(struct pcap *pcap);
|
||||||
|
|
||||||
bool pcap_read(struct pcap *pcap, struct timeval *tv,
|
bool pcap_read(struct pcap *pcap, struct timeval *tv,
|
||||||
void *data, uint32_t size, uint32_t *len, uint32_t *real_len);
|
void *data, uint32_t size, uint32_t *len, uint32_t *real_len);
|
||||||
|
|||||||
@ -94,13 +94,13 @@ static void adhoc_sta_free(void *data)
|
|||||||
eapol_sm_free(sta->sm);
|
eapol_sm_free(sta->sm);
|
||||||
|
|
||||||
if (sta->hs_sta)
|
if (sta->hs_sta)
|
||||||
handshake_state_free(sta->hs_sta);
|
handshake_state_unref(sta->hs_sta);
|
||||||
|
|
||||||
if (sta->sm_a)
|
if (sta->sm_a)
|
||||||
eapol_sm_free(sta->sm_a);
|
eapol_sm_free(sta->sm_a);
|
||||||
|
|
||||||
if (sta->hs_auth)
|
if (sta->hs_auth)
|
||||||
handshake_state_free(sta->hs_auth);
|
handshake_state_unref(sta->hs_auth);
|
||||||
|
|
||||||
end:
|
end:
|
||||||
l_free(sta);
|
l_free(sta);
|
||||||
|
|||||||
@ -234,7 +234,7 @@ uint32_t anqp_request(uint64_t wdev_id, const uint8_t *addr,
|
|||||||
request->anqp_cb = cb;
|
request->anqp_cb = cb;
|
||||||
request->anqp_destroy = destroy;
|
request->anqp_destroy = destroy;
|
||||||
/*
|
/*
|
||||||
* WPA3 Specificiation version 3, Section 9.4:
|
* WPA3 Specification version 3, Section 9.4:
|
||||||
* "A STA shall use a randomized dialog token for every new GAS
|
* "A STA shall use a randomized dialog token for every new GAS
|
||||||
* exchange."
|
* exchange."
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -131,7 +131,7 @@ char **anqp_parse_nai_realms(const unsigned char *anqp, unsigned int len)
|
|||||||
uint16_t count;
|
uint16_t count;
|
||||||
|
|
||||||
if (len < 2)
|
if (len < 2)
|
||||||
return false;
|
return NULL;
|
||||||
|
|
||||||
count = l_get_le16(anqp);
|
count = l_get_le16(anqp);
|
||||||
|
|
||||||
|
|||||||
108
src/ap.c
108
src/ap.c
@ -67,7 +67,7 @@ struct ap_state {
|
|||||||
ap_stopped_func_t stopped_func;
|
ap_stopped_func_t stopped_func;
|
||||||
void *user_data;
|
void *user_data;
|
||||||
|
|
||||||
char ssid[33];
|
char ssid[SSID_MAX_SIZE + 1];
|
||||||
char passphrase[64];
|
char passphrase[64];
|
||||||
uint8_t psk[32];
|
uint8_t psk[32];
|
||||||
enum band_freq band;
|
enum band_freq band;
|
||||||
@ -109,6 +109,8 @@ struct ap_state {
|
|||||||
struct l_timeout *rekey_timeout;
|
struct l_timeout *rekey_timeout;
|
||||||
unsigned int rekey_time;
|
unsigned int rekey_time;
|
||||||
|
|
||||||
|
uint32_t pre_scan_cmd_id;
|
||||||
|
|
||||||
bool started : 1;
|
bool started : 1;
|
||||||
bool gtk_set : 1;
|
bool gtk_set : 1;
|
||||||
bool netconfig_set_addr4 : 1;
|
bool netconfig_set_addr4 : 1;
|
||||||
@ -153,7 +155,7 @@ struct ap_wsc_pbc_probe_record {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ap_network {
|
struct ap_network {
|
||||||
char ssid[33];
|
char ssid[SSID_MAX_SIZE + 1];
|
||||||
int16_t signal;
|
int16_t signal;
|
||||||
enum security security;
|
enum security security;
|
||||||
};
|
};
|
||||||
@ -181,7 +183,7 @@ static int network_signal_compare(const void *a, const void *b, void *user)
|
|||||||
static struct ap_network *ap_network_find(struct ap_state *ap,
|
static struct ap_network *ap_network_find(struct ap_state *ap,
|
||||||
struct scan_bss *bss)
|
struct scan_bss *bss)
|
||||||
{
|
{
|
||||||
char ssid[33];
|
char ssid[SSID_MAX_SIZE + 1];
|
||||||
|
|
||||||
memcpy(ssid, bss->ssid, bss->ssid_len);
|
memcpy(ssid, bss->ssid, bss->ssid_len);
|
||||||
ssid[bss->ssid_len] = '\0';
|
ssid[bss->ssid_len] = '\0';
|
||||||
@ -230,7 +232,7 @@ static void ap_stop_handshake(struct sta_state *sta)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sta->hs) {
|
if (sta->hs) {
|
||||||
handshake_state_free(sta->hs);
|
handshake_state_unref(sta->hs);
|
||||||
sta->hs = NULL;
|
sta->hs = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,6 +356,12 @@ static void ap_reset(struct ap_state *ap)
|
|||||||
l_timeout_remove(ap->rekey_timeout);
|
l_timeout_remove(ap->rekey_timeout);
|
||||||
ap->rekey_timeout = NULL;
|
ap->rekey_timeout = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ap->pre_scan_cmd_id) {
|
||||||
|
scan_cancel(netdev_get_wdev_id(ap->netdev),
|
||||||
|
ap->pre_scan_cmd_id);
|
||||||
|
ap->pre_scan_cmd_id = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ap_event_done(struct ap_state *ap, bool prev_in_event)
|
static bool ap_event_done(struct ap_state *ap, bool prev_in_event)
|
||||||
@ -3629,7 +3637,7 @@ static int ap_load_config(struct ap_state *ap, const struct l_settings *config,
|
|||||||
return -ENOMSG;
|
return -ENOMSG;
|
||||||
|
|
||||||
len = strlen(strval);
|
len = strlen(strval);
|
||||||
if (len < 1 || len > 32) {
|
if (len < 1 || len > SSID_MAX_SIZE) {
|
||||||
l_error("AP SSID length outside the [1, 32] range");
|
l_error("AP SSID length outside the [1, 32] range");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -3852,6 +3860,70 @@ static int ap_load_config(struct ap_state *ap, const struct l_settings *config,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ap_pre_scan_trigger(int err, void *user_data)
|
||||||
|
{
|
||||||
|
struct ap_state *ap = user_data;
|
||||||
|
|
||||||
|
if (err < 0) {
|
||||||
|
l_error("AP pre-scan failed: %i", err);
|
||||||
|
ap_start_failed(ap, err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ap_check_channel(struct ap_state *ap)
|
||||||
|
{
|
||||||
|
const struct band_freq_attrs *freq_attr;
|
||||||
|
|
||||||
|
freq_attr = wiphy_get_frequency_info(netdev_get_wiphy(ap->netdev),
|
||||||
|
band_channel_to_freq(ap->channel, ap->band));
|
||||||
|
if (L_WARN_ON(!freq_attr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Check if disabled/no-IR */
|
||||||
|
if (freq_attr->disabled || freq_attr->no_ir)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ap_pre_scan_notify(int err, struct l_queue *bss_list,
|
||||||
|
const struct scan_freq_set *freqs,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
struct ap_state *ap = user_data;
|
||||||
|
|
||||||
|
if (!ap_check_channel(ap)) {
|
||||||
|
l_error("Unable to channel %u even after pre-scan",
|
||||||
|
ap->channel);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ap_start_send(ap))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
error:
|
||||||
|
ap_start_failed(ap, -ENOTSUP);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ap_pre_scan_destroy(void *user_data)
|
||||||
|
{
|
||||||
|
struct ap_state *ap = user_data;
|
||||||
|
|
||||||
|
ap->pre_scan_cmd_id = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ap_pre_scan(struct ap_state *ap)
|
||||||
|
{
|
||||||
|
ap->pre_scan_cmd_id = scan_passive(netdev_get_wdev_id(ap->netdev),
|
||||||
|
NULL, ap_pre_scan_trigger,
|
||||||
|
ap_pre_scan_notify,
|
||||||
|
ap, ap_pre_scan_destroy);
|
||||||
|
|
||||||
|
return ap->pre_scan_cmd_id != 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Start a simple independent WPA2 AP on given netdev.
|
* Start a simple independent WPA2 AP on given netdev.
|
||||||
*
|
*
|
||||||
@ -3914,34 +3986,34 @@ struct ap_state *ap_start(struct netdev *netdev, struct l_settings *config,
|
|||||||
|
|
||||||
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
||||||
(MPDU_MANAGEMENT_SUBTYPE_ASSOCIATION_REQUEST << 4),
|
(MPDU_MANAGEMENT_SUBTYPE_ASSOCIATION_REQUEST << 4),
|
||||||
NULL, 0, ap_assoc_req_cb, ap, NULL))
|
NULL, 0, false, ap_assoc_req_cb, ap, NULL))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
||||||
(MPDU_MANAGEMENT_SUBTYPE_REASSOCIATION_REQUEST << 4),
|
(MPDU_MANAGEMENT_SUBTYPE_REASSOCIATION_REQUEST << 4),
|
||||||
NULL, 0, ap_reassoc_req_cb, ap, NULL))
|
NULL, 0, false, ap_reassoc_req_cb, ap, NULL))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!wiphy_supports_probe_resp_offload(wiphy)) {
|
if (!wiphy_supports_probe_resp_offload(wiphy)) {
|
||||||
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
||||||
(MPDU_MANAGEMENT_SUBTYPE_PROBE_REQUEST << 4),
|
(MPDU_MANAGEMENT_SUBTYPE_PROBE_REQUEST << 4),
|
||||||
NULL, 0, ap_probe_req_cb, ap, NULL))
|
NULL, 0, false, ap_probe_req_cb, ap, NULL))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
||||||
(MPDU_MANAGEMENT_SUBTYPE_DISASSOCIATION << 4),
|
(MPDU_MANAGEMENT_SUBTYPE_DISASSOCIATION << 4),
|
||||||
NULL, 0, ap_disassoc_cb, ap, NULL))
|
NULL, 0, false, ap_disassoc_cb, ap, NULL))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
||||||
(MPDU_MANAGEMENT_SUBTYPE_AUTHENTICATION << 4),
|
(MPDU_MANAGEMENT_SUBTYPE_AUTHENTICATION << 4),
|
||||||
NULL, 0, ap_auth_cb, ap, NULL))
|
NULL, 0, false, ap_auth_cb, ap, NULL))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
if (!frame_watch_add(wdev_id, 0, 0x0000 |
|
||||||
(MPDU_MANAGEMENT_SUBTYPE_DEAUTHENTICATION << 4),
|
(MPDU_MANAGEMENT_SUBTYPE_DEAUTHENTICATION << 4),
|
||||||
NULL, 0, ap_deauth_cb, ap, NULL))
|
NULL, 0, false, ap_deauth_cb, ap, NULL))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
ap->mlme_watch = l_genl_family_register(ap->nl80211, "mlme",
|
ap->mlme_watch = l_genl_family_register(ap->nl80211, "mlme",
|
||||||
@ -3962,6 +4034,20 @@ struct ap_state *ap_start(struct netdev *netdev, struct l_settings *config,
|
|||||||
return ap;
|
return ap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ap_check_channel(ap)) {
|
||||||
|
l_debug("Channel %u is disabled/no-IR, pre-scanning",
|
||||||
|
ap->channel);
|
||||||
|
|
||||||
|
if (ap_pre_scan(ap)) {
|
||||||
|
if (err_out)
|
||||||
|
*err_out = 0;
|
||||||
|
|
||||||
|
return ap;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
if (ap_start_send(ap)) {
|
if (ap_start_send(ap)) {
|
||||||
if (err_out)
|
if (err_out)
|
||||||
*err_out = 0;
|
*err_out = 0;
|
||||||
|
|||||||
2
src/ap.h
2
src/ap.h
@ -79,7 +79,7 @@ struct ap_ops {
|
|||||||
void *user_data);
|
void *user_data);
|
||||||
/*
|
/*
|
||||||
* If not null, writes extra IEs to be added to the outgoing frame of
|
* If not null, writes extra IEs to be added to the outgoing frame of
|
||||||
* given type and, if it's not a beacon frame, in reponse to a given
|
* given type and, if it's not a beacon frame, in response to a given
|
||||||
* client frame. May also react to the extra IEs in that frame.
|
* client frame. May also react to the extra IEs in that frame.
|
||||||
* Returns the number of bytes written which must be less than or
|
* Returns the number of bytes written which must be less than or
|
||||||
* equal to the number returned by .get_extra_ies_len when called
|
* equal to the number returned by .get_extra_ies_len when called
|
||||||
|
|||||||
@ -54,7 +54,7 @@ void __iwd_backtrace_print(unsigned int offset)
|
|||||||
int pathlen;
|
int pathlen;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
if (program_exec == NULL)
|
if (!program_exec)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pathlen = strlen(program_path);
|
pathlen = strlen(program_path);
|
||||||
@ -186,7 +186,7 @@ void __iwd_backtrace_init(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (program_exec == NULL)
|
if (!program_exec)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
program_path = getcwd(cwd, sizeof(cwd));
|
program_path = getcwd(cwd, sizeof(cwd));
|
||||||
|
|||||||
68
src/band.c
68
src/band.c
@ -678,7 +678,7 @@ int band_estimate_he_rx_rate(const struct band *band, const uint8_t *hec,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!rate)
|
if (!rate)
|
||||||
return -EBADMSG;
|
return -ENETUNREACH;
|
||||||
|
|
||||||
*out_data_rate = rate;
|
*out_data_rate = rate;
|
||||||
|
|
||||||
@ -896,7 +896,7 @@ static const struct operating_class_info e4_operating_classes[] = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
.operating_class = 136,
|
.operating_class = 136,
|
||||||
.starting_frequency = 5950,
|
.starting_frequency = 5925,
|
||||||
.channel_spacing = 20,
|
.channel_spacing = 20,
|
||||||
.center_frequencies = { 2 },
|
.center_frequencies = { 2 },
|
||||||
}
|
}
|
||||||
@ -1352,6 +1352,10 @@ check_e4:
|
|||||||
const struct operating_class_info *info =
|
const struct operating_class_info *info =
|
||||||
&e4_operating_classes[i];
|
&e4_operating_classes[i];
|
||||||
|
|
||||||
|
if (band != band_oper_class_to_band(NULL,
|
||||||
|
info->operating_class))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (e4_has_frequency(info, freq) == 0 ||
|
if (e4_has_frequency(info, freq) == 0 ||
|
||||||
e4_has_ccfi(info, freq) == 0) {
|
e4_has_ccfi(info, freq) == 0) {
|
||||||
if (out_band)
|
if (out_band)
|
||||||
@ -1426,7 +1430,7 @@ static const char *const oper_class_eu_codes[] = {
|
|||||||
"AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE",
|
"AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE",
|
||||||
"DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT",
|
"DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT",
|
||||||
"LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT",
|
"LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT",
|
||||||
"RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK"
|
"RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK", "GB"
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Annex E, table E-1 */
|
/* Annex E, table E-1 */
|
||||||
@ -1485,15 +1489,48 @@ static const uint8_t oper_class_cn_to_global[] = {
|
|||||||
/* 128 - 130 is a 1 to 1 mapping */
|
/* 128 - 130 is a 1 to 1 mapping */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum band_freq band_oper_class_to_band(const uint8_t *country,
|
/*
|
||||||
uint8_t oper_class)
|
* Annex C describes the country string encoding.
|
||||||
|
*
|
||||||
|
* If it is a country, the first two octets of this string is the two character
|
||||||
|
* country code as described in document ISO 3166-1. The third octet is one of
|
||||||
|
* the following:
|
||||||
|
* 1. an ASCII space character, if the regulations under which the station is
|
||||||
|
* operating encompass all environments for the current frequency band in
|
||||||
|
* the country,
|
||||||
|
* 2. an ASCII 'O' character, if the regulations under which the station is
|
||||||
|
* operating are for an outdoor environment only, or
|
||||||
|
* 3. an ASCII 'I' character, if the regulations under which the station is
|
||||||
|
* operating are for an indoor environment only.
|
||||||
|
* 4. an ASCII 'X' character, if the station is operating under a noncountry
|
||||||
|
* entity. The first two octets of the noncountry entity is two ASCII 'XX'
|
||||||
|
* characters.
|
||||||
|
* 5. the hexadecimal representation of the Operating Class table number
|
||||||
|
* currently in use, from the set of tables defined in Annex E, e.g.,
|
||||||
|
* Table E-1 is represented as x'01'.
|
||||||
|
*/
|
||||||
|
static enum band_freq oper_class_to_band(const uint8_t *country,
|
||||||
|
uint8_t oper_class,
|
||||||
|
bool ignore_country3)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int table = 0;
|
int table = 0;
|
||||||
|
|
||||||
if (country && country[2] >= 1 && country[2] <= 5)
|
/*
|
||||||
|
* If a country is set, and the 3rd byte maps to some E-* table in the
|
||||||
|
* spec use that (case 5). Only caveat here is some APs erroneously set
|
||||||
|
* this 3rd byte. To work around we can fall back to case 1, where only
|
||||||
|
* the first two characters are used to lookup the table.
|
||||||
|
*/
|
||||||
|
if (!ignore_country3 && country && country[2] >= 1 && country[2] <= 5)
|
||||||
table = country[2];
|
table = country[2];
|
||||||
else if (country) {
|
else if (country) {
|
||||||
|
/*
|
||||||
|
* Assuming case 1, although its unlikely you would handle
|
||||||
|
* cases 2 (O) or 3 (I) any differently. Case 4 (X) is unlikely
|
||||||
|
* and we really wouldn't have enough information to correctly
|
||||||
|
* determine the band in some obscure non-country domain.
|
||||||
|
*/
|
||||||
for (i = 0; i < L_ARRAY_SIZE(oper_class_us_codes); i++)
|
for (i = 0; i < L_ARRAY_SIZE(oper_class_us_codes); i++)
|
||||||
if (!memcmp(oper_class_us_codes[i], country, 2)) {
|
if (!memcmp(oper_class_us_codes[i], country, 2)) {
|
||||||
/* Use table E-1 */
|
/* Use table E-1 */
|
||||||
@ -1542,6 +1579,25 @@ enum band_freq band_oper_class_to_band(const uint8_t *country,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum band_freq band_oper_class_to_band(const uint8_t *country,
|
||||||
|
uint8_t oper_class)
|
||||||
|
{
|
||||||
|
enum band_freq band = oper_class_to_band(country, oper_class, false);
|
||||||
|
if (!band) {
|
||||||
|
/* Fallback with no country string won't change anything */
|
||||||
|
if (!country)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
l_warn("Failed to find band with country string '%c%c %u' and "
|
||||||
|
"oper class %u, trying fallback",
|
||||||
|
country[0], country[1], country[2], oper_class);
|
||||||
|
|
||||||
|
return oper_class_to_band(country, oper_class, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return band;
|
||||||
|
}
|
||||||
|
|
||||||
const char *band_chandef_width_to_string(enum band_chandef_width width)
|
const char *band_chandef_width_to_string(enum band_chandef_width width)
|
||||||
{
|
{
|
||||||
switch (width) {
|
switch (width) {
|
||||||
|
|||||||
128
src/blacklist.c
128
src/blacklist.c
@ -45,22 +45,42 @@
|
|||||||
|
|
||||||
static uint64_t blacklist_multiplier;
|
static uint64_t blacklist_multiplier;
|
||||||
static uint64_t blacklist_initial_timeout;
|
static uint64_t blacklist_initial_timeout;
|
||||||
|
static uint64_t blacklist_ap_busy_initial_timeout;
|
||||||
static uint64_t blacklist_max_timeout;
|
static uint64_t blacklist_max_timeout;
|
||||||
|
|
||||||
struct blacklist_entry {
|
struct blacklist_entry {
|
||||||
uint8_t addr[6];
|
uint8_t addr[6];
|
||||||
uint64_t added_time;
|
uint64_t added_time;
|
||||||
uint64_t expire_time;
|
uint64_t expire_time;
|
||||||
|
enum blacklist_reason reason;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct blacklist_search {
|
||||||
|
const uint8_t *addr;
|
||||||
|
enum blacklist_reason reason;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct l_queue *blacklist;
|
static struct l_queue *blacklist;
|
||||||
|
|
||||||
|
static uint64_t get_reason_timeout(enum blacklist_reason reason)
|
||||||
|
{
|
||||||
|
switch (reason) {
|
||||||
|
case BLACKLIST_REASON_CONNECT_FAILED:
|
||||||
|
return blacklist_initial_timeout;
|
||||||
|
case BLACKLIST_REASON_AP_BUSY:
|
||||||
|
return blacklist_ap_busy_initial_timeout;
|
||||||
|
default:
|
||||||
|
l_warn("Unhandled blacklist reason: %u", reason);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool check_if_expired(void *data, void *user_data)
|
static bool check_if_expired(void *data, void *user_data)
|
||||||
{
|
{
|
||||||
struct blacklist_entry *entry = data;
|
struct blacklist_entry *entry = data;
|
||||||
uint64_t now = l_get_u64(user_data);
|
uint64_t now = l_get_u64(user_data);
|
||||||
|
|
||||||
if (l_time_diff(now, entry->added_time) > blacklist_max_timeout) {
|
if (l_time_after(now, entry->expire_time)) {
|
||||||
l_debug("Removing entry "MAC" on prune", MAC_STR(entry->addr));
|
l_debug("Removing entry "MAC" on prune", MAC_STR(entry->addr));
|
||||||
l_free(entry);
|
l_free(entry);
|
||||||
return true;
|
return true;
|
||||||
@ -87,17 +107,53 @@ static bool match_addr(const void *a, const void *b)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void blacklist_add_bss(const uint8_t *addr)
|
static bool match_addr_and_reason(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const struct blacklist_entry *entry = a;
|
||||||
|
const struct blacklist_search *search = b;
|
||||||
|
|
||||||
|
if (entry->reason != search->reason)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!memcmp(entry->addr, search->addr, 6))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void blacklist_add_bss(const uint8_t *addr, enum blacklist_reason reason)
|
||||||
{
|
{
|
||||||
struct blacklist_entry *entry;
|
struct blacklist_entry *entry;
|
||||||
|
uint64_t timeout;
|
||||||
|
|
||||||
blacklist_prune();
|
blacklist_prune();
|
||||||
|
|
||||||
|
timeout = get_reason_timeout(reason);
|
||||||
|
if (!timeout)
|
||||||
|
return;
|
||||||
|
|
||||||
entry = l_queue_find(blacklist, match_addr, addr);
|
entry = l_queue_find(blacklist, match_addr, addr);
|
||||||
|
|
||||||
if (entry) {
|
if (entry) {
|
||||||
uint64_t offset = l_time_diff(entry->added_time,
|
uint64_t offset;
|
||||||
entry->expire_time);
|
|
||||||
|
if (reason < entry->reason) {
|
||||||
|
l_debug("Promoting "MAC" blacklist to reason %u",
|
||||||
|
MAC_STR(addr), reason);
|
||||||
|
/* Reset this to the new timeout and reason */
|
||||||
|
entry->reason = reason;
|
||||||
|
entry->added_time = l_time_now();
|
||||||
|
entry->expire_time = l_time_offset(entry->added_time,
|
||||||
|
timeout);
|
||||||
|
return;
|
||||||
|
} else if (reason > entry->reason) {
|
||||||
|
l_debug("Ignoring blacklist extension of "MAC", "
|
||||||
|
"current blacklist status is more severe!",
|
||||||
|
MAC_STR(addr));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = l_time_diff(entry->added_time, entry->expire_time);
|
||||||
|
|
||||||
offset *= blacklist_multiplier;
|
offset *= blacklist_multiplier;
|
||||||
|
|
||||||
@ -112,40 +168,36 @@ void blacklist_add_bss(const uint8_t *addr)
|
|||||||
entry = l_new(struct blacklist_entry, 1);
|
entry = l_new(struct blacklist_entry, 1);
|
||||||
|
|
||||||
entry->added_time = l_time_now();
|
entry->added_time = l_time_now();
|
||||||
entry->expire_time = l_time_offset(entry->added_time,
|
entry->expire_time = l_time_offset(entry->added_time, timeout);
|
||||||
blacklist_initial_timeout);
|
entry->reason = reason;
|
||||||
memcpy(entry->addr, addr, 6);
|
memcpy(entry->addr, addr, 6);
|
||||||
|
|
||||||
l_queue_push_tail(blacklist, entry);
|
l_queue_push_tail(blacklist, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool blacklist_contains_bss(const uint8_t *addr)
|
bool blacklist_contains_bss(const uint8_t *addr, enum blacklist_reason reason)
|
||||||
{
|
{
|
||||||
bool ret;
|
struct blacklist_search search = {
|
||||||
uint64_t time_now;
|
.addr = addr,
|
||||||
struct blacklist_entry *entry;
|
.reason = reason
|
||||||
|
};
|
||||||
|
|
||||||
blacklist_prune();
|
blacklist_prune();
|
||||||
|
|
||||||
entry = l_queue_find(blacklist, match_addr, addr);
|
return l_queue_find(blacklist, match_addr_and_reason, &search) != NULL;
|
||||||
|
|
||||||
if (!entry)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
time_now = l_time_now();
|
|
||||||
|
|
||||||
ret = l_time_after(time_now, entry->expire_time) ? false : true;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void blacklist_remove_bss(const uint8_t *addr)
|
void blacklist_remove_bss(const uint8_t *addr, enum blacklist_reason reason)
|
||||||
{
|
{
|
||||||
struct blacklist_entry *entry;
|
struct blacklist_entry *entry;
|
||||||
|
struct blacklist_search search = {
|
||||||
|
.addr = addr,
|
||||||
|
.reason = reason
|
||||||
|
};
|
||||||
|
|
||||||
blacklist_prune();
|
blacklist_prune();
|
||||||
|
|
||||||
entry = l_queue_remove_if(blacklist, match_addr, addr);
|
entry = l_queue_remove_if(blacklist, match_addr_and_reason, &search);
|
||||||
|
|
||||||
if (!entry)
|
if (!entry)
|
||||||
return;
|
return;
|
||||||
@ -162,19 +214,47 @@ static int blacklist_init(void)
|
|||||||
blacklist_initial_timeout = BLACKLIST_DEFAULT_TIMEOUT;
|
blacklist_initial_timeout = BLACKLIST_DEFAULT_TIMEOUT;
|
||||||
|
|
||||||
/* For easier user configuration the timeout values are in seconds */
|
/* For easier user configuration the timeout values are in seconds */
|
||||||
blacklist_initial_timeout *= 1000000;
|
blacklist_initial_timeout *= L_USEC_PER_SEC;
|
||||||
|
|
||||||
|
if (!l_settings_get_uint64(config, "Blacklist",
|
||||||
|
"InitialRoamRequestedTimeout",
|
||||||
|
&blacklist_ap_busy_initial_timeout))
|
||||||
|
blacklist_ap_busy_initial_timeout = BLACKLIST_DEFAULT_TIMEOUT;
|
||||||
|
else
|
||||||
|
l_warn("[Blacklist].InitialRoamRequestedTimeout is deprecated, "
|
||||||
|
"use [Blacklist].InitialAccessPointBusyTimeout");
|
||||||
|
|
||||||
|
if (!l_settings_get_uint64(config, "Blacklist",
|
||||||
|
"InitialAccessPointBusyTimeout",
|
||||||
|
&blacklist_ap_busy_initial_timeout))
|
||||||
|
blacklist_ap_busy_initial_timeout = BLACKLIST_DEFAULT_TIMEOUT;
|
||||||
|
|
||||||
|
/* For easier user configuration the timeout values are in seconds */
|
||||||
|
blacklist_ap_busy_initial_timeout *= L_USEC_PER_SEC;
|
||||||
|
|
||||||
if (!l_settings_get_uint64(config, "Blacklist",
|
if (!l_settings_get_uint64(config, "Blacklist",
|
||||||
"Multiplier",
|
"Multiplier",
|
||||||
&blacklist_multiplier))
|
&blacklist_multiplier))
|
||||||
blacklist_multiplier = BLACKLIST_DEFAULT_MULTIPLIER;
|
blacklist_multiplier = BLACKLIST_DEFAULT_MULTIPLIER;
|
||||||
|
|
||||||
|
if (blacklist_multiplier == 0) {
|
||||||
|
l_warn("[Blacklist].Multiplier cannot be zero, setting to 1");
|
||||||
|
blacklist_multiplier = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!l_settings_get_uint64(config, "Blacklist",
|
if (!l_settings_get_uint64(config, "Blacklist",
|
||||||
"MaximumTimeout",
|
"MaximumTimeout",
|
||||||
&blacklist_max_timeout))
|
&blacklist_max_timeout))
|
||||||
blacklist_max_timeout = BLACKLIST_DEFAULT_MAX_TIMEOUT;
|
blacklist_max_timeout = BLACKLIST_DEFAULT_MAX_TIMEOUT;
|
||||||
|
|
||||||
blacklist_max_timeout *= 1000000;
|
blacklist_max_timeout *= L_USEC_PER_SEC;
|
||||||
|
|
||||||
|
if (blacklist_initial_timeout > blacklist_max_timeout)
|
||||||
|
l_warn("[Blacklist].InitialTimeout exceeded "
|
||||||
|
"[Blacklist].MaximumTimeout!");
|
||||||
|
|
||||||
|
if (!blacklist_initial_timeout)
|
||||||
|
l_debug("initial timeout was zero, blacklist will be disabled");
|
||||||
|
|
||||||
blacklist = l_queue_new();
|
blacklist = l_queue_new();
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,23 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void blacklist_add_bss(const uint8_t *addr);
|
enum blacklist_reason {
|
||||||
bool blacklist_contains_bss(const uint8_t *addr);
|
/*
|
||||||
void blacklist_remove_bss(const uint8_t *addr);
|
* When a BSS is blacklisted using this reason IWD will refuse to
|
||||||
|
* connect to it via autoconnect
|
||||||
|
*/
|
||||||
|
BLACKLIST_REASON_CONNECT_FAILED,
|
||||||
|
/*
|
||||||
|
* This type of blacklist is added when an AP indicates that its unable
|
||||||
|
* to handle more connections. This is done via BSS-TM requests or
|
||||||
|
* denied authentications/associations with certain status codes.
|
||||||
|
*
|
||||||
|
* Once this type of blacklist is applied to a BSS IWD will attempt to
|
||||||
|
* avoid roaming to it for a configured period of time.
|
||||||
|
*/
|
||||||
|
BLACKLIST_REASON_AP_BUSY,
|
||||||
|
};
|
||||||
|
|
||||||
|
void blacklist_add_bss(const uint8_t *addr, enum blacklist_reason reason);
|
||||||
|
bool blacklist_contains_bss(const uint8_t *addr, enum blacklist_reason reason);
|
||||||
|
void blacklist_remove_bss(const uint8_t *addr, enum blacklist_reason reason);
|
||||||
|
|||||||
@ -35,6 +35,7 @@
|
|||||||
|
|
||||||
#include "ell/useful.h"
|
#include "ell/useful.h"
|
||||||
#include "src/missing.h"
|
#include "src/missing.h"
|
||||||
|
#include "src/defs.h"
|
||||||
#include "src/crypto.h"
|
#include "src/crypto.h"
|
||||||
|
|
||||||
#define ARC4_MIN_KEY_SIZE 1
|
#define ARC4_MIN_KEY_SIZE 1
|
||||||
@ -567,7 +568,7 @@ int crypto_psk_from_passphrase(const char *passphrase,
|
|||||||
if (!crypto_passphrase_is_valid(passphrase))
|
if (!crypto_passphrase_is_valid(passphrase))
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
if (ssid_len == 0 || ssid_len > 32)
|
if (ssid_len == 0 || ssid_len > SSID_MAX_SIZE)
|
||||||
return -ERANGE;
|
return -ERANGE;
|
||||||
|
|
||||||
result = l_cert_pkcs5_pbkdf2(L_CHECKSUM_SHA1, passphrase,
|
result = l_cert_pkcs5_pbkdf2(L_CHECKSUM_SHA1, passphrase,
|
||||||
@ -1211,7 +1212,7 @@ struct l_ecc_point *crypto_derive_sae_pwe_from_pt_ecc(const uint8_t *mac1,
|
|||||||
struct l_ecc_point *pwe;
|
struct l_ecc_point *pwe;
|
||||||
|
|
||||||
if (!pt || !curve)
|
if (!pt || !curve)
|
||||||
return false;
|
return NULL;
|
||||||
|
|
||||||
hash = crypto_sae_hash_from_ecc_prime_len(CRYPTO_SAE_HASH_TO_ELEMENT,
|
hash = crypto_sae_hash_from_ecc_prime_len(CRYPTO_SAE_HASH_TO_ELEMENT,
|
||||||
l_ecc_curve_get_scalar_bytes(curve));
|
l_ecc_curve_get_scalar_bytes(curve));
|
||||||
|
|||||||
@ -134,6 +134,12 @@ struct l_dbus_message *dbus_error_not_hidden(struct l_dbus_message *msg)
|
|||||||
"Not hidden");
|
"Not hidden");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct l_dbus_message *dbus_error_permission_denied(struct l_dbus_message *msg)
|
||||||
|
{
|
||||||
|
return l_dbus_message_new_error(msg, IWD_SERVICE ".PermissionDenied",
|
||||||
|
"Permission Denied");
|
||||||
|
}
|
||||||
|
|
||||||
struct l_dbus_message *dbus_error_from_errno(int err,
|
struct l_dbus_message *dbus_error_from_errno(int err,
|
||||||
struct l_dbus_message *msg)
|
struct l_dbus_message *msg)
|
||||||
{
|
{
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user