summaryrefslogtreecommitdiff
path: root/src/network/networkd-wifi.c
blob: 94195d778ffb15d8d3f32aeef10001c4425ba74b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* SPDX-License-Identifier: LGPL-2.1+ */

#include <net/ethernet.h>
#include <linux/nl80211.h>

#include "sd-bus.h"

#include "bus-util.h"
#include "netlink-internal.h"
#include "netlink-util.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-wifi.h"
#include "string-util.h"

static int wifi_get_ssid(Link *link) {
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
        _cleanup_free_ char *ssid = NULL;
        sd_genl_family family;
        int r;

        r = sd_genl_message_new(link->manager->genl, SD_GENL_NL80211, NL80211_CMD_GET_INTERFACE, &m);
        if (r < 0)
                return log_link_error_errno(link, r, "Failed to create generic netlink message: %m");

        r = sd_netlink_message_append_u32(m, NL80211_ATTR_IFINDEX, link->ifindex);
        if (r < 0)
                return log_link_error_errno(link, r, "Could not append NL80211_ATTR_IFINDEX attribute: %m");

        r = sd_netlink_call(link->manager->genl, m, 0, &reply);
        if (r < 0)
                return log_link_error_errno(link, r, "Failed to request information about wifi interface: %m");
        if (!reply)
                return 0;

        r = sd_netlink_message_get_errno(reply);
        if (r < 0)
                return log_link_warning_errno(link, r, "Failed to get information about wifi interface: %m");

        r = sd_genl_message_get_family(link->manager->genl, reply, &family);
        if (r < 0)
                return log_link_warning_errno(link, r, "Failed to determine genl family: %m");
        if (family != SD_GENL_NL80211) {
                log_link_debug(link, "Received message of unexpected genl family %u, ignoring.", family);
                return 0;
        }

        r = sd_netlink_message_read_string_strdup(reply, NL80211_ATTR_SSID, &ssid);
        if (r < 0 && r != -ENODATA)
                return log_link_warning_errno(link, r, "Failed to get NL80211_ATTR_SSID attribute: %m");

        free_and_replace(link->ssid, ssid);
        return r == -ENODATA ? 0 : 1;
}

static int wifi_get_bssid(Link *link) {
        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL;
        struct ether_addr mac = {};
        sd_genl_family family;
        int r;

        assert(link);
        assert(link->manager);
        assert(link->manager->genl);

        r = sd_genl_message_new(link->manager->genl, SD_GENL_NL80211, NL80211_CMD_GET_STATION, &m);
        if (r < 0)
                return log_link_error_errno(link, r, "Failed to create generic netlink message: %m");

        r = sd_netlink_message_set_flags(m, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
        if (r < 0)
                return log_link_error_errno(link, r, "Failed to set dump flag: %m");

        r = sd_netlink_message_append_u32(m, NL80211_ATTR_IFINDEX, link->ifindex);
        if (r < 0)
                return log_link_error_errno(link, r, "Could not append NL80211_ATTR_IFINDEX attribute: %m");

        r = sd_netlink_call(link->manager->genl, m, 0, &reply);
        if (r < 0)
                return log_link_error_errno(link, r, "Failed to request information about wifi station: %m");
        if (!reply)
                return 0;

        r = sd_netlink_message_get_errno(reply);
        if (r < 0)
                return log_link_error_errno(link, r, "Failed to get information about wifi station: %m");

        r = sd_genl_message_get_family(link->manager->genl, reply, &family);
        if (r < 0)
                return log_link_warning_errno(link, r, "Failed to determine genl family: %m");
        if (family != SD_GENL_NL80211) {
                log_link_debug(link, "Received message of unexpected genl family %u, ignoring.", family);
                return 0;
        }

        r = sd_netlink_message_read_ether_addr(reply, NL80211_ATTR_MAC, &mac);
        if (r < 0 && r != -ENODATA)
                return log_link_warning_errno(link, r, "Failed to get NL80211_ATTR_MAC attribute: %m");

        r = memcmp(&link->bssid, &mac, sizeof(mac));
        if (r == 0)
                return 0;

        memcpy(&link->bssid, &mac, sizeof(mac));
        return 1;
}

int wifi_get_info(Link *link) {
        char buf[ETHER_ADDR_TO_STRING_MAX];
        const char *type;
        int r, s;

        assert(link);

        if (!link->sd_device)
                return 0;

        r = sd_device_get_devtype(link->sd_device, &type);
        if (r == -ENOENT)
                return 0;
        else if (r < 0)
                return r;

        if (!streq(type, "wlan"))
                return 0;

        r = wifi_get_ssid(link);
        if (r < 0)
                return r;

        s = wifi_get_bssid(link);
        if (s < 0)
                return s;

        if (r > 0 || s > 0) {
                if (link->ssid)
                        log_link_info(link, "Connected WiFi access point: %s (%s)",
                                      link->ssid, ether_addr_to_string(&link->bssid, buf));
                return 1;
        }
        return 0;
}