2
2
3
3
use std:: env:: args;
4
4
5
- use anyhow:: { bail, Context , Error } ;
6
- use futures:: stream:: TryStreamExt ;
5
+ use anyhow:: { anyhow, bail, Context , Result } ;
6
+ use futures:: { stream:: TryStreamExt , StreamExt } ;
7
+ use netlink_packet_core:: { NetlinkMessage , NetlinkPayload , NLM_F_REQUEST } ;
8
+ use netlink_packet_generic:: {
9
+ ctrl:: {
10
+ nlas:: { GenlCtrlAttrs , McastGrpAttrs } ,
11
+ GenlCtrl , GenlCtrlCmd ,
12
+ } ,
13
+ GenlMessage ,
14
+ } ;
15
+ use netlink_packet_utils:: ParseableParametrized ;
16
+ use netlink_sys:: AsyncSocket ;
17
+ use wl_nl80211:: { Nl80211Attr , Nl80211Command , Nl80211Message } ;
7
18
8
- fn main ( ) -> Result < ( ) , Error > {
19
+ fn main ( ) -> Result < ( ) > {
9
20
let argv: Vec < _ > = args ( ) . collect ( ) ;
10
21
11
22
if argv. len ( ) < 2 {
@@ -21,13 +32,20 @@ fn main() -> Result<(), Error> {
21
32
. enable_time ( )
22
33
. build ( )
23
34
. unwrap ( ) ;
24
- rt. block_on ( dump_scan ( index) ) ;
35
+ rt. block_on ( dump_scan ( index) ) ? ;
25
36
26
37
Ok ( ( ) )
27
38
}
28
39
29
- async fn dump_scan ( if_index : u32 ) {
30
- let ( connection, handle, _) = wl_nl80211:: new_connection ( ) . unwrap ( ) ;
40
+ async fn dump_scan ( if_index : u32 ) -> Result < ( ) > {
41
+ let ( mut connection, handle, mut messages) = wl_nl80211:: new_connection ( ) ?;
42
+
43
+ // Attach the connection socket to the multicast scan group to find out,
44
+ // when the scan is finished.
45
+ let socket = connection. socket_mut ( ) . socket_mut ( ) ;
46
+ socket. bind_auto ( ) ?;
47
+ socket. add_membership ( get_scan_multicast_id ( ) . await ?) ?;
48
+
31
49
tokio:: spawn ( connection) ;
32
50
33
51
let attrs = wl_nl80211:: Nl80211Scan :: new ( if_index)
@@ -41,7 +59,23 @@ async fn dump_scan(if_index: u32) {
41
59
while let Some ( msg) = scan_handle. try_next ( ) . await . unwrap ( ) {
42
60
msgs. push ( msg) ;
43
61
}
44
- tokio:: time:: sleep ( std:: time:: Duration :: from_secs ( 5 ) ) . await ;
62
+
63
+ while let Some ( ( message, _) ) = messages. next ( ) . await {
64
+ match message. payload {
65
+ NetlinkPayload :: InnerMessage ( msg) => {
66
+ let msg = Nl80211Message :: parse_with_param (
67
+ msg. payload . as_slice ( ) ,
68
+ msg. header ,
69
+ ) ?;
70
+ if msg. cmd == Nl80211Command :: NewScanResults
71
+ && msg. attributes . contains ( & Nl80211Attr :: IfIndex ( if_index) )
72
+ {
73
+ break ;
74
+ }
75
+ }
76
+ _ => continue ,
77
+ }
78
+ }
45
79
46
80
let mut dump = handle. scan ( ) . dump ( if_index) . execute ( ) . await ;
47
81
let mut msgs = Vec :: new ( ) ;
@@ -52,4 +86,65 @@ async fn dump_scan(if_index: u32) {
52
86
for msg in msgs {
53
87
println ! ( "{msg:?}" ) ;
54
88
}
89
+
90
+ Ok ( ( ) )
91
+ }
92
+
93
+ async fn get_scan_multicast_id ( ) -> Result < u32 > {
94
+ let ( conn, mut handle, _) = wl_nl80211:: new_connection ( ) ?;
95
+ tokio:: spawn ( conn) ;
96
+
97
+ let mut nl_msg =
98
+ NetlinkMessage :: from ( GenlMessage :: from_payload ( GenlCtrl {
99
+ cmd : GenlCtrlCmd :: GetFamily ,
100
+ nlas : vec ! [ GenlCtrlAttrs :: FamilyName ( "nl80211" . to_owned( ) ) ] ,
101
+ } ) ) ;
102
+
103
+ // To get the mcast groups for the nl80211 family, we must also set the
104
+ // message type id
105
+ nl_msg. header . message_type =
106
+ handle. handle . resolve_family_id :: < Nl80211Message > ( ) . await ?;
107
+ // This is a request, but not a dump. Which means, the family name has to be
108
+ // specified, to obtain it's information.
109
+ nl_msg. header . flags = NLM_F_REQUEST ;
110
+
111
+ let responses = handle. handle . request ( nl_msg) . await ?;
112
+ let nl80211_family: Vec < Vec < GenlCtrlAttrs > > = responses
113
+ . try_filter_map ( |msg| async move {
114
+ match msg. payload {
115
+ NetlinkPayload :: InnerMessage ( genlmsg)
116
+ if genlmsg. payload . cmd == GenlCtrlCmd :: NewFamily
117
+ && genlmsg. payload . nlas . contains (
118
+ & GenlCtrlAttrs :: FamilyName ( "nl80211" . to_owned ( ) ) ,
119
+ ) =>
120
+ {
121
+ Ok ( Some ( genlmsg. payload . nlas . clone ( ) ) )
122
+ }
123
+ _ => Ok ( None ) ,
124
+ }
125
+ } )
126
+ . try_collect ( )
127
+ . await ?;
128
+
129
+ // Now get the mcid for "nl80211" "scan" group
130
+ let scan_multicast_id = nl80211_family
131
+ . first ( )
132
+ . ok_or_else ( || anyhow ! ( "Missing \" nl80211\" family" ) ) ?
133
+ . iter ( )
134
+ . find_map ( |attr| match attr {
135
+ GenlCtrlAttrs :: McastGroups ( mcast_groups) => Some ( mcast_groups) ,
136
+ _ => None ,
137
+ } )
138
+ . ok_or_else ( || anyhow ! ( "Missing McastGroup attribute" ) ) ?
139
+ . iter ( )
140
+ . find ( |grp| grp. contains ( & McastGrpAttrs :: Name ( "scan" . to_owned ( ) ) ) )
141
+ . ok_or_else ( || anyhow ! ( "Missing scan group" ) ) ?
142
+ . iter ( )
143
+ . find_map ( |grp_attr| match grp_attr {
144
+ McastGrpAttrs :: Id ( id) => Some ( * id) ,
145
+ _ => None ,
146
+ } )
147
+ . ok_or_else ( || anyhow ! ( "No multicast id defined for scan group" ) ) ?;
148
+
149
+ Ok ( scan_multicast_id)
55
150
}
0 commit comments