11use crate :: {
22 backend:: traits:: WifiBackend ,
3- domain:: wifi:: { WifiNetwork , WifiState } ,
3+ domain:: wifi:: { WifiDeviceInfo , WifiNetwork , WifiState } ,
44} ;
55use anyhow:: Result ;
66use std:: collections:: HashSet ;
@@ -38,6 +38,7 @@ impl WifiBackend for IwdBackend {
3838 let connected_ssid = parse_connected_network ( & iface) ;
3939 let mut known_networks = parse_known_networks ( ) ;
4040 let mut new_networks = parse_networks ( & iface) ;
41+ let station_info = parse_station_info ( & iface) ;
4142
4243 if let Some ( conn) = & connected_ssid {
4344 for n in & mut known_networks {
@@ -56,11 +57,25 @@ impl WifiBackend for IwdBackend {
5657 let known_ssids: HashSet < & str > = known_networks. iter ( ) . map ( |n| n. ssid . as_str ( ) ) . collect ( ) ;
5758 new_networks. retain ( |n| !known_ssids. contains ( n. ssid . as_str ( ) ) ) ;
5859
60+ let security = station_info. security . unwrap_or_else ( || {
61+ infer_connected_security ( & known_networks, & new_networks)
62+ . unwrap_or_else ( || "-" . to_string ( ) )
63+ } ) ;
64+
5965 Ok ( WifiState {
6066 ifaces,
6167 connected_ssid,
6268 known_networks,
6369 new_networks,
70+ device : Some ( WifiDeviceInfo {
71+ iface : iface. clone ( ) ,
72+ mode : "station" . to_string ( ) ,
73+ powered : "On" . to_string ( ) ,
74+ state : station_info. state . unwrap_or_else ( || "-" . to_string ( ) ) ,
75+ scanning : station_info. scanning . unwrap_or_else ( || "-" . to_string ( ) ) ,
76+ frequency : station_info. frequency . unwrap_or_else ( || "-" . to_string ( ) ) ,
77+ security,
78+ } ) ,
6479 } )
6580 }
6681}
@@ -157,6 +172,8 @@ fn parse_networks(iface: &str) -> Vec<WifiNetwork> {
157172 security,
158173 signal,
159174 connected,
175+ hidden : None ,
176+ autoconnect : None ,
160177 } ) ;
161178 }
162179
@@ -202,12 +219,75 @@ fn parse_known_networks() -> Vec<WifiNetwork> {
202219 security,
203220 signal : "-" . to_string ( ) ,
204221 connected : false ,
222+ hidden : None ,
223+ autoconnect : None ,
205224 } ) ;
206225 }
207226
208227 nets
209228}
210229
230+ #[ derive( Default ) ]
231+ struct StationInfo {
232+ state : Option < String > ,
233+ scanning : Option < String > ,
234+ frequency : Option < String > ,
235+ security : Option < String > ,
236+ }
237+
238+ fn parse_station_info ( iface : & str ) -> StationInfo {
239+ let out = std:: process:: Command :: new ( "iwctl" )
240+ . arg ( "station" )
241+ . arg ( iface)
242+ . arg ( "show" )
243+ . output ( ) ;
244+
245+ let Ok ( out) = out else {
246+ return StationInfo :: default ( ) ;
247+ } ;
248+ if !out. status . success ( ) {
249+ return StationInfo :: default ( ) ;
250+ }
251+
252+ let txt = String :: from_utf8_lossy ( & out. stdout ) ;
253+ let mut info = StationInfo :: default ( ) ;
254+
255+ for raw in txt. lines ( ) {
256+ let line = raw. trim ( ) ;
257+ if let Some ( v) = value_after_key ( line, "State" ) {
258+ info. state = Some ( v. to_string ( ) ) ;
259+ } else if let Some ( v) = value_after_key ( line, "Scanning" ) {
260+ info. scanning = Some ( v. to_string ( ) ) ;
261+ } else if let Some ( v) = value_after_key ( line, "Frequency" ) {
262+ info. frequency = Some ( v. to_string ( ) ) ;
263+ } else if let Some ( v) = value_after_key ( line, "Security" ) {
264+ info. security = Some ( v. to_string ( ) ) ;
265+ }
266+ }
267+
268+ info
269+ }
270+
271+ fn value_after_key < ' a > ( line : & ' a str , key : & str ) -> Option < & ' a str > {
272+ if !line. starts_with ( key) {
273+ return None ;
274+ }
275+ let mut rest = & line[ key. len ( ) ..] ;
276+ rest = rest. trim ( ) ;
277+ if let Some ( stripped) = rest. strip_prefix ( ':' ) {
278+ rest = stripped. trim ( ) ;
279+ }
280+ if rest. is_empty ( ) { None } else { Some ( rest) }
281+ }
282+
283+ fn infer_connected_security ( known : & [ WifiNetwork ] , new : & [ WifiNetwork ] ) -> Option < String > {
284+ known
285+ . iter ( )
286+ . find ( |n| n. connected )
287+ . map ( |n| n. security . clone ( ) )
288+ . or_else ( || new. iter ( ) . find ( |n| n. connected ) . map ( |n| n. security . clone ( ) ) )
289+ }
290+
211291async fn run_iwctl ( args : & [ & str ] ) -> Result < ( ) > {
212292 let out = Command :: new ( "iwctl" ) . args ( args) . output ( ) . await ?;
213293 if out. status . success ( ) {
0 commit comments