Skip to content

Commit e99e7c6

Browse files
committed
networkmanager: Add Wi-Fi support
Update the model to collect Wi-Fi access points and provide a scan method. On a Wi-Fi device page, show a table of available networks with mode, signal strength, rate, and security status. The currently active connection (if any) is always at the top, followed by known networks (with a saved connection), then unknown networks sorted by descending signal strength (by default, the table can also be sorted by name), and finally the number of hidden networks. Allow the user to connect, disconnect, and forget networks, and re-scan. In the Networking overview, if there are any Wi-Fi devices, add a "Details" column which shows the number of available and the currently connected networks. We can test this with `mac80211_hwsim` and `hostapd`, to create the kinds of networks that we want to cover: one open (with two APs), two WPA (so that we can have one active and one inactive one), and one hidden network. https://issues.redhat.com/browse/COCKPIT-1751
1 parent d01fca7 commit e99e7c6

File tree

6 files changed

+1142
-17
lines changed

6 files changed

+1142
-17
lines changed

pkg/networkmanager/interfaces.js

Lines changed: 102 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -610,6 +610,13 @@ export function NetworkManagerModel() {
610610
};
611611
}
612612

613+
if (settings["802-11-wireless"]) {
614+
result["802-11-wireless"] = {
615+
ssid: get("802-11-wireless", "ssid"),
616+
mode: get("802-11-wireless", "mode"),
617+
};
618+
}
619+
613620
return result;
614621
}
615622

@@ -784,6 +791,20 @@ export function NetworkManagerModel() {
784791
delete result.wireguard;
785792
}
786793

794+
if (settings["802-11-wireless"]) {
795+
set("802-11-wireless", "ssid", 'ay', settings["802-11-wireless"].ssid);
796+
set("802-11-wireless", "mode", 's', settings["802-11-wireless"].mode);
797+
} else {
798+
delete result["802-11-wireless"];
799+
}
800+
801+
if (settings["802-11-wireless-security"]) {
802+
set("802-11-wireless-security", "key-mgmt", 's', settings["802-11-wireless-security"]["key-mgmt"]);
803+
set("802-11-wireless-security", "psk", 's', settings["802-11-wireless-security"].psk);
804+
} else {
805+
delete result["802-11-wireless-security"];
806+
}
807+
787808
return result;
788809
}
789810

@@ -860,6 +881,21 @@ export function NetworkManagerModel() {
860881
}
861882
}
862883

884+
function access_point_mode_to_text(mode) {
885+
switch (mode) {
886+
// NM_802_11_MODE_ADHOC
887+
case 1: return _("Adhoc");
888+
// NM_802_11_MODE_INFRA
889+
case 2: return _("Infra");
890+
// NM_802_11_MODE_AP
891+
case 3: return _("AP");
892+
// NM_802_11_MODE_MESH
893+
case 4: return _("Mesh");
894+
// subsumes NM_802_11_MODE_UNKNOWN
895+
default: return _("Unknown");
896+
}
897+
}
898+
863899
const connections_by_uuid = { };
864900

865901
function set_settings(obj, settings) {
@@ -942,6 +978,37 @@ export function NetworkManagerModel() {
942978
}
943979
};
944980

981+
const type_AccessPoint = {
982+
interfaces: [
983+
"org.freedesktop.NetworkManager.AccessPoint"
984+
],
985+
986+
props: {
987+
Flags: { def: 0 },
988+
WpaFlags: { def: 0 },
989+
RsnFlags: { def: 0 },
990+
Ssid: { conv: utils.ssid_from_nm, def: "" },
991+
Frequency: { def: 0 }, // MHz
992+
HwAddress: { def: "" },
993+
Mode: { conv: access_point_mode_to_text, def: "" },
994+
MaxBitrate: { def: 0 }, // Kbit/s
995+
Bandwidth: { def: 0 }, // MHz
996+
Strength: { def: 0 },
997+
LastSeen: { def: -1 }, // CLOCK_BOOTTIME seconds, -1 if never seen
998+
},
999+
1000+
exporters: [
1001+
function (obj) {
1002+
// Find connection for this SSID (undefined if none exists)
1003+
obj.Connection = (self.get_settings()?.Connections || []).find(con => {
1004+
if (con.Settings?.["802-11-wireless"]?.ssid)
1005+
return utils.ssid_from_nm(con.Settings["802-11-wireless"].ssid) == obj.Ssid;
1006+
return false;
1007+
});
1008+
}
1009+
]
1010+
};
1011+
9451012
const type_Connection = {
9461013
interfaces: [
9471014
"org.freedesktop.NetworkManager.Settings.Connection"
@@ -1052,7 +1119,8 @@ export function NetworkManagerModel() {
10521119
props: {
10531120
Connection: { conv: conv_Object(type_Connection) },
10541121
Ip4Config: { conv: conv_Object(type_Ipv4Config) },
1055-
Ip6Config: { conv: conv_Object(type_Ipv6Config) }
1122+
Ip6Config: { conv: conv_Object(type_Ipv6Config) },
1123+
State: { def: 0 }
10561124
// See below for "Group"
10571125
},
10581126

@@ -1073,7 +1141,8 @@ export function NetworkManagerModel() {
10731141
"org.freedesktop.NetworkManager.Device.Bond",
10741142
"org.freedesktop.NetworkManager.Device.Team",
10751143
"org.freedesktop.NetworkManager.Device.Bridge",
1076-
"org.freedesktop.NetworkManager.Device.Vlan"
1144+
"org.freedesktop.NetworkManager.Device.Vlan",
1145+
"org.freedesktop.NetworkManager.Device.Wireless"
10771146
],
10781147

10791148
props: {
@@ -1093,6 +1162,9 @@ export function NetworkManagerModel() {
10931162
Carrier: { def: true },
10941163
Speed: { },
10951164
Managed: { def: false },
1165+
// WiFi-specific properties
1166+
AccessPoints: { conv: conv_Array(conv_Object(type_AccessPoint)), def: [] },
1167+
ActiveAccessPoint: { conv: conv_Object(type_AccessPoint) },
10961168
// See below for "Members"
10971169
},
10981170

@@ -1109,7 +1181,10 @@ export function NetworkManagerModel() {
11091181
return call_object_method(get_object("/org/freedesktop/NetworkManager", type_Manager),
11101182
"org.freedesktop.NetworkManager", "AddAndActivateConnection",
11111183
settings_to_nm(settings), objpath(this), objpath(specific_object))
1112-
.then(([path, active_connection]) => active_connection);
1184+
.then(([path, active_connection_path]) => ({
1185+
connection: get_object(path, type_Connection),
1186+
active_connection: get_object(active_connection_path, type_ActiveConnection)
1187+
}));
11131188
} catch (e) {
11141189
return Promise.reject(e);
11151190
}
@@ -1118,8 +1193,29 @@ export function NetworkManagerModel() {
11181193
disconnect: function () {
11191194
return call_object_method(this, 'org.freedesktop.NetworkManager.Device', 'Disconnect')
11201195
.then(() => undefined);
1196+
},
1197+
1198+
// Request a WiFi scan to populate this.AccessPoints
1199+
request_scan: function() {
1200+
utils.debug("request_scan: requesting scan for", this.Interface);
1201+
call_object_method(this, 'org.freedesktop.NetworkManager.Device.Wireless', 'RequestScan', {})
1202+
.catch(error => {
1203+
// RequestScan can fail if a scan was recently done, that's OK
1204+
console.warn("request_scan: scan failed for", this.Interface + ":", error.toString());
1205+
});
11211206
}
1122-
}
1207+
},
1208+
1209+
exporters: [
1210+
function (obj) {
1211+
// Once we see any WiFi device, trigger one initial scan
1212+
if (obj.DeviceType === '802-11-wireless' && !priv(obj).wifi_scan_requested) {
1213+
utils.debug("triggering initial WiFi scan for", obj.Interface);
1214+
priv(obj).wifi_scan_requested = true;
1215+
obj.request_scan();
1216+
}
1217+
}
1218+
]
11231219
};
11241220

11251221
// The 'Interface' type does not correspond to any NetworkManager
@@ -1362,7 +1458,8 @@ export function NetworkManagerModel() {
13621458
type_Ipv4Config,
13631459
type_Ipv6Config,
13641460
type_Connection,
1365-
type_ActiveConnection
1461+
type_ActiveConnection,
1462+
type_AccessPoint
13661463
]);
13671464

13681465
get_object("/org/freedesktop/NetworkManager", type_Manager);

0 commit comments

Comments
 (0)