1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "sd-netlink.h"
5 #include "alloc-util.h"
6 #include "ether-addr-util.h"
8 #include "string-table.h"
9 #include "string-util.h"
10 #include "wifi-util.h"
12 int wifi_get_interface(sd_netlink
*genl
, int ifindex
, enum nl80211_iftype
*ret_iftype
, char **ret_ssid
) {
13 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
, *reply
= NULL
;
14 _cleanup_free_
char *ssid
= NULL
;
23 r
= sd_genl_message_new(genl
, NL80211_GENL_NAME
, NL80211_CMD_GET_INTERFACE
, &m
);
25 return log_debug_errno(r
, "Failed to create generic netlink message: %m");
27 r
= sd_netlink_message_append_u32(m
, NL80211_ATTR_IFINDEX
, ifindex
);
29 return log_debug_errno(r
, "Could not append NL80211_ATTR_IFINDEX attribute: %m");
31 r
= sd_netlink_call(genl
, m
, 0, &reply
);
33 /* For obsolete WEXT driver. */
34 log_debug_errno(r
, "Failed to request information about wifi interface %d. "
35 "The device doesn't seem to have nl80211 interface. Ignoring.",
40 return log_debug_errno(r
, "Failed to request information about wifi interface %d: %m", ifindex
);
42 log_debug("No reply received to request for information about wifi interface %d, ignoring.", ifindex
);
46 r
= sd_netlink_message_get_errno(reply
);
48 return log_debug_errno(r
, "Failed to get information about wifi interface %d: %m", ifindex
);
50 r
= sd_genl_message_get_family_name(genl
, reply
, &family
);
52 return log_debug_errno(r
, "Failed to determine genl family: %m");
53 if (!streq(family
, NL80211_GENL_NAME
)) {
54 log_debug("Received message of unexpected genl family '%s', ignoring.", family
);
58 r
= sd_netlink_message_read_u32(reply
, NL80211_ATTR_IFTYPE
, &iftype
);
60 return log_debug_errno(r
, "Failed to get NL80211_ATTR_IFTYPE attribute: %m");
62 r
= sd_netlink_message_read_data(reply
, NL80211_ATTR_SSID
, &len
, (void**) &ssid
);
63 if (r
< 0 && r
!= -ENODATA
)
64 return log_debug_errno(r
, "Failed to get NL80211_ATTR_SSID attribute: %m");
67 log_debug("SSID has zero length, ignoring it.");
69 } else if (strlen_ptr(ssid
) != len
) {
70 log_debug("SSID contains NUL characters, ignoring it.");
79 *ret_ssid
= TAKE_PTR(ssid
);
91 int wifi_get_station(sd_netlink
*genl
, int ifindex
, struct ether_addr
*ret_bssid
) {
92 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
, *reply
= NULL
;
100 r
= sd_genl_message_new(genl
, NL80211_GENL_NAME
, NL80211_CMD_GET_STATION
, &m
);
102 return log_debug_errno(r
, "Failed to create generic netlink message: %m");
104 r
= sd_netlink_message_set_flags(m
, NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
106 return log_debug_errno(r
, "Failed to set dump flag: %m");
108 r
= sd_netlink_message_append_u32(m
, NL80211_ATTR_IFINDEX
, ifindex
);
110 return log_debug_errno(r
, "Could not append NL80211_ATTR_IFINDEX attribute: %m");
112 r
= sd_netlink_call(genl
, m
, 0, &reply
);
114 return log_debug_errno(r
, "Failed to request information about wifi station: %m");
116 log_debug("No reply received to request for information about wifi station, ignoring.");
120 r
= sd_netlink_message_get_errno(reply
);
122 return log_debug_errno(r
, "Failed to get information about wifi station: %m");
124 r
= sd_genl_message_get_family_name(genl
, reply
, &family
);
126 return log_debug_errno(r
, "Failed to determine genl family: %m");
127 if (!streq(family
, NL80211_GENL_NAME
)) {
128 log_debug("Received message of unexpected genl family '%s', ignoring.", family
);
132 r
= sd_netlink_message_read_ether_addr(reply
, NL80211_ATTR_MAC
, ret_bssid
);
136 return log_debug_errno(r
, "Failed to get NL80211_ATTR_MAC attribute: %m");
141 *ret_bssid
= ETHER_ADDR_NULL
;
145 static const char * const nl80211_iftype_table
[NUM_NL80211_IFTYPES
] = {
146 [NL80211_IFTYPE_ADHOC
] = "ad-hoc",
147 [NL80211_IFTYPE_STATION
] = "station",
148 [NL80211_IFTYPE_AP
] = "ap",
149 [NL80211_IFTYPE_AP_VLAN
] = "ap-vlan",
150 [NL80211_IFTYPE_WDS
] = "wds",
151 [NL80211_IFTYPE_MONITOR
] = "monitor",
152 [NL80211_IFTYPE_MESH_POINT
] = "mesh-point",
153 [NL80211_IFTYPE_P2P_CLIENT
] = "p2p-client",
154 [NL80211_IFTYPE_P2P_GO
] = "p2p-go",
155 [NL80211_IFTYPE_P2P_DEVICE
] = "p2p-device",
156 [NL80211_IFTYPE_OCB
] = "ocb",
157 [NL80211_IFTYPE_NAN
] = "nan",
160 DEFINE_STRING_TABLE_LOOKUP(nl80211_iftype
, enum nl80211_iftype
);
162 static const char * const nl80211_cmd_table
[__NL80211_CMD_AFTER_LAST
] = {
163 [NL80211_CMD_GET_WIPHY
] = "get_wiphy",
164 [NL80211_CMD_SET_WIPHY
] = "set_wiphy",
165 [NL80211_CMD_NEW_WIPHY
] = "new_wiphy",
166 [NL80211_CMD_DEL_WIPHY
] = "del_wiphy",
167 [NL80211_CMD_GET_INTERFACE
] = "get_interface",
168 [NL80211_CMD_SET_INTERFACE
] = "set_interface",
169 [NL80211_CMD_NEW_INTERFACE
] = "new_interface",
170 [NL80211_CMD_DEL_INTERFACE
] = "del_interface",
171 [NL80211_CMD_GET_KEY
] = "get_key",
172 [NL80211_CMD_SET_KEY
] = "set_key",
173 [NL80211_CMD_NEW_KEY
] = "new_key",
174 [NL80211_CMD_DEL_KEY
] = "del_key",
175 [NL80211_CMD_GET_BEACON
] = "get_beacon",
176 [NL80211_CMD_SET_BEACON
] = "set_beacon",
177 [NL80211_CMD_START_AP
] = "start_ap",
178 [NL80211_CMD_STOP_AP
] = "stop_ap",
179 [NL80211_CMD_GET_STATION
] = "get_station",
180 [NL80211_CMD_SET_STATION
] = "set_station",
181 [NL80211_CMD_NEW_STATION
] = "new_station",
182 [NL80211_CMD_DEL_STATION
] = "del_station",
183 [NL80211_CMD_GET_MPATH
] = "get_mpath",
184 [NL80211_CMD_SET_MPATH
] = "set_mpath",
185 [NL80211_CMD_NEW_MPATH
] = "new_mpath",
186 [NL80211_CMD_DEL_MPATH
] = "del_mpath",
187 [NL80211_CMD_SET_BSS
] = "set_bss",
188 [NL80211_CMD_SET_REG
] = "set_reg",
189 [NL80211_CMD_REQ_SET_REG
] = "req_set_reg",
190 [NL80211_CMD_GET_MESH_CONFIG
] = "get_mesh_config",
191 [NL80211_CMD_SET_MESH_CONFIG
] = "set_mesh_config",
192 [NL80211_CMD_SET_MGMT_EXTRA_IE
] = "set_mgmt_extra_ie",
193 [NL80211_CMD_GET_REG
] = "get_reg",
194 [NL80211_CMD_GET_SCAN
] = "get_scan",
195 [NL80211_CMD_TRIGGER_SCAN
] = "trigger_scan",
196 [NL80211_CMD_NEW_SCAN_RESULTS
] = "new_scan_results",
197 [NL80211_CMD_SCAN_ABORTED
] = "scan_aborted",
198 [NL80211_CMD_REG_CHANGE
] = "reg_change",
199 [NL80211_CMD_AUTHENTICATE
] = "authenticate",
200 [NL80211_CMD_ASSOCIATE
] = "associate",
201 [NL80211_CMD_DEAUTHENTICATE
] = "deauthenticate",
202 [NL80211_CMD_DISASSOCIATE
] = "disassociate",
203 [NL80211_CMD_MICHAEL_MIC_FAILURE
] = "michael_mic_failure",
204 [NL80211_CMD_REG_BEACON_HINT
] = "reg_beacon_hint",
205 [NL80211_CMD_JOIN_IBSS
] = "join_ibss",
206 [NL80211_CMD_LEAVE_IBSS
] = "leave_ibss",
207 [NL80211_CMD_TESTMODE
] = "testmode",
208 [NL80211_CMD_CONNECT
] = "connect",
209 [NL80211_CMD_ROAM
] = "roam",
210 [NL80211_CMD_DISCONNECT
] = "disconnect",
211 [NL80211_CMD_SET_WIPHY_NETNS
] = "set_wiphy_netns",
212 [NL80211_CMD_GET_SURVEY
] = "get_survey",
213 [NL80211_CMD_NEW_SURVEY_RESULTS
] = "new_survey_results",
214 [NL80211_CMD_SET_PMKSA
] = "set_pmksa",
215 [NL80211_CMD_DEL_PMKSA
] = "del_pmksa",
216 [NL80211_CMD_FLUSH_PMKSA
] = "flush_pmksa",
217 [NL80211_CMD_REMAIN_ON_CHANNEL
] = "remain_on_channel",
218 [NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL
] = "cancel_remain_on_channel",
219 [NL80211_CMD_SET_TX_BITRATE_MASK
] = "set_tx_bitrate_mask",
220 [NL80211_CMD_REGISTER_FRAME
] = "register_frame",
221 [NL80211_CMD_FRAME
] = "frame",
222 [NL80211_CMD_FRAME_TX_STATUS
] = "frame_tx_status",
223 [NL80211_CMD_SET_POWER_SAVE
] = "set_power_save",
224 [NL80211_CMD_GET_POWER_SAVE
] = "get_power_save",
225 [NL80211_CMD_SET_CQM
] = "set_cqm",
226 [NL80211_CMD_NOTIFY_CQM
] = "notify_cqm",
227 [NL80211_CMD_SET_CHANNEL
] = "set_channel",
228 [NL80211_CMD_SET_WDS_PEER
] = "set_wds_peer",
229 [NL80211_CMD_FRAME_WAIT_CANCEL
] = "frame_wait_cancel",
230 [NL80211_CMD_JOIN_MESH
] = "join_mesh",
231 [NL80211_CMD_LEAVE_MESH
] = "leave_mesh",
232 [NL80211_CMD_UNPROT_DEAUTHENTICATE
] = "unprot_deauthenticate",
233 [NL80211_CMD_UNPROT_DISASSOCIATE
] = "unprot_disassociate",
234 [NL80211_CMD_NEW_PEER_CANDIDATE
] = "new_peer_candidate",
235 [NL80211_CMD_GET_WOWLAN
] = "get_wowlan",
236 [NL80211_CMD_SET_WOWLAN
] = "set_wowlan",
237 [NL80211_CMD_START_SCHED_SCAN
] = "start_sched_scan",
238 [NL80211_CMD_STOP_SCHED_SCAN
] = "stop_sched_scan",
239 [NL80211_CMD_SCHED_SCAN_RESULTS
] = "sched_scan_results",
240 [NL80211_CMD_SCHED_SCAN_STOPPED
] = "sched_scan_stopped",
241 [NL80211_CMD_SET_REKEY_OFFLOAD
] = "set_rekey_offload",
242 [NL80211_CMD_PMKSA_CANDIDATE
] = "pmksa_candidate",
243 [NL80211_CMD_TDLS_OPER
] = "tdls_oper",
244 [NL80211_CMD_TDLS_MGMT
] = "tdls_mgmt",
245 [NL80211_CMD_UNEXPECTED_FRAME
] = "unexpected_frame",
246 [NL80211_CMD_PROBE_CLIENT
] = "probe_client",
247 [NL80211_CMD_REGISTER_BEACONS
] = "register_beacons",
248 [NL80211_CMD_UNEXPECTED_4ADDR_FRAME
] = "unexpected_4addr_frame",
249 [NL80211_CMD_SET_NOACK_MAP
] = "set_noack_map",
250 [NL80211_CMD_CH_SWITCH_NOTIFY
] = "ch_switch_notify",
251 [NL80211_CMD_START_P2P_DEVICE
] = "start_p2p_device",
252 [NL80211_CMD_STOP_P2P_DEVICE
] = "stop_p2p_device",
253 [NL80211_CMD_CONN_FAILED
] = "conn_failed",
254 [NL80211_CMD_SET_MCAST_RATE
] = "set_mcast_rate",
255 [NL80211_CMD_SET_MAC_ACL
] = "set_mac_acl",
256 [NL80211_CMD_RADAR_DETECT
] = "radar_detect",
257 [NL80211_CMD_GET_PROTOCOL_FEATURES
] = "get_protocol_features",
258 [NL80211_CMD_UPDATE_FT_IES
] = "update_ft_ies",
259 [NL80211_CMD_FT_EVENT
] = "ft_event",
260 [NL80211_CMD_CRIT_PROTOCOL_START
] = "crit_protocol_start",
261 [NL80211_CMD_CRIT_PROTOCOL_STOP
] = "crit_protocol_stop",
262 [NL80211_CMD_GET_COALESCE
] = "get_coalesce",
263 [NL80211_CMD_SET_COALESCE
] = "set_coalesce",
264 [NL80211_CMD_CHANNEL_SWITCH
] = "channel_switch",
265 [NL80211_CMD_VENDOR
] = "vendor",
266 [NL80211_CMD_SET_QOS_MAP
] = "set_qos_map",
267 [NL80211_CMD_ADD_TX_TS
] = "add_tx_ts",
268 [NL80211_CMD_DEL_TX_TS
] = "del_tx_ts",
269 [NL80211_CMD_GET_MPP
] = "get_mpp",
270 [NL80211_CMD_JOIN_OCB
] = "join_ocb",
271 [NL80211_CMD_LEAVE_OCB
] = "leave_ocb",
272 [NL80211_CMD_CH_SWITCH_STARTED_NOTIFY
] = "ch_switch_started_notify",
273 [NL80211_CMD_TDLS_CHANNEL_SWITCH
] = "tdls_channel_switch",
274 [NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH
] = "tdls_cancel_channel_switch",
275 [NL80211_CMD_WIPHY_REG_CHANGE
] = "wiphy_reg_change",
276 [NL80211_CMD_ABORT_SCAN
] = "abort_scan",
277 [NL80211_CMD_START_NAN
] = "start_nan",
278 [NL80211_CMD_STOP_NAN
] = "stop_nan",
279 [NL80211_CMD_ADD_NAN_FUNCTION
] = "add_nan_function",
280 [NL80211_CMD_DEL_NAN_FUNCTION
] = "del_nan_function",
281 [NL80211_CMD_CHANGE_NAN_CONFIG
] = "change_nan_config",
282 [NL80211_CMD_NAN_MATCH
] = "nan_match",
283 [NL80211_CMD_SET_MULTICAST_TO_UNICAST
] = "set_multicast_to_unicast",
284 [NL80211_CMD_UPDATE_CONNECT_PARAMS
] = "update_connect_params",
285 [NL80211_CMD_SET_PMK
] = "set_pmk",
286 [NL80211_CMD_DEL_PMK
] = "del_pmk",
287 [NL80211_CMD_PORT_AUTHORIZED
] = "port_authorized",
288 [NL80211_CMD_RELOAD_REGDB
] = "reload_regdb",
289 [NL80211_CMD_EXTERNAL_AUTH
] = "external_auth",
290 [NL80211_CMD_STA_OPMODE_CHANGED
] = "sta_opmode_changed",
291 [NL80211_CMD_CONTROL_PORT_FRAME
] = "control_port_frame",
292 [NL80211_CMD_GET_FTM_RESPONDER_STATS
] = "get_ftm_responder_stats",
293 [NL80211_CMD_PEER_MEASUREMENT_START
] = "peer_measurement_start",
294 [NL80211_CMD_PEER_MEASUREMENT_RESULT
] = "peer_measurement_result",
295 [NL80211_CMD_PEER_MEASUREMENT_COMPLETE
] = "peer_measurement_complete",
296 [NL80211_CMD_NOTIFY_RADAR
] = "notify_radar",
297 [NL80211_CMD_UPDATE_OWE_INFO
] = "update_owe_info",
298 [NL80211_CMD_PROBE_MESH_LINK
] = "probe_mesh_link",
299 [NL80211_CMD_SET_TID_CONFIG
] = "set_tid_config",
300 [NL80211_CMD_UNPROT_BEACON
] = "unprot_beacon",
301 [NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS
] = "control_port_frame_tx_status",
302 [NL80211_CMD_SET_SAR_SPECS
] = "set_sar_specs",
303 [NL80211_CMD_OBSS_COLOR_COLLISION
] = "obss_color_collision",
304 [NL80211_CMD_COLOR_CHANGE_REQUEST
] = "color_change_request",
305 [NL80211_CMD_COLOR_CHANGE_STARTED
] = "color_change_started",
306 [NL80211_CMD_COLOR_CHANGE_ABORTED
] = "color_change_aborted",
307 [NL80211_CMD_COLOR_CHANGE_COMPLETED
] = "color_change_completed",
310 DEFINE_STRING_TABLE_LOOKUP_TO_STRING(nl80211_cmd
, int);