1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-08 21:17:47 +03:00

Merge pull request #13142 from yuwata/network-wifi-ssid-support-nl80211

network: wifi ssid support with nl80211
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2019-10-23 14:51:23 +02:00 committed by GitHub
commit 510c4bb31f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 542 additions and 70 deletions

View File

@ -153,6 +153,24 @@
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>SSID=</varname></term>
<listitem>
<para>A whitespace-separated list of shell-style globs matching the SSID of the currently
connected wireless LAN. If the list is prefixed with a "!", the test is inverted.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>BSSID=</varname></term>
<listitem>
<para>A whitespace-separated list of hardware address of the currently connected wireless
LAN. Use full colon-, hyphen- or dot-delimited hexadecimal. See the example in
<varname>MACAddress=</varname>. This option may appear more than one, in which case the
lists are merged. If the empty string is assigned to this option, the list of BSSID defined
prior to this is reset.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Host=</varname></term>
<listitem>

View File

@ -142,9 +142,13 @@ bool net_match_config(Set *match_mac,
char * const *match_types,
char * const *match_names,
char * const *match_property,
char * const *match_ssid,
Set *match_bssid,
sd_device *device,
const struct ether_addr *dev_mac,
const char *dev_name) {
const char *dev_name,
const char *ssid,
const struct ether_addr *bssid) {
const char *dev_path = NULL, *dev_driver = NULL, *dev_type = NULL, *mac_str;
@ -178,6 +182,12 @@ bool net_match_config(Set *match_mac,
if (!net_condition_test_property(match_property, device))
return false;
if (!net_condition_test_strv(match_ssid, ssid))
return false;
if (match_bssid && (!bssid || !set_contains(match_bssid, bssid)))
return false;
return true;
}

View File

@ -20,9 +20,13 @@ bool net_match_config(Set *match_mac,
char * const *match_type,
char * const *match_name,
char * const *match_property,
char * const *match_ssid,
Set *match_bssid,
sd_device *device,
const struct ether_addr *dev_mac,
const char *dev_name);
const char *dev_name,
const char *ssid,
const struct ether_addr *bssid);
CONFIG_PARSER_PROTOTYPE(config_parse_net_condition);
CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr);

View File

@ -71,6 +71,7 @@ libsystemd_sources = files('''
sd-hwdb/hwdb-util.h
sd-hwdb/sd-hwdb.c
sd-netlink/generic-netlink.c
sd-netlink/generic-netlink.h
sd-netlink/netlink-internal.h
sd-netlink/netlink-message.c
sd-netlink/netlink-slot.c

View File

@ -1,8 +1,12 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <linux/genetlink.h>
#include "sd-netlink.h"
#include "netlink-internal.h"
#include "alloc-util.h"
#include "generic-netlink.h"
#include "netlink-internal.h"
typedef struct {
const char* name;
@ -15,6 +19,7 @@ static const genl_family genl_families[] = {
[SD_GENL_FOU] = { .name = "fou", .version = 1 },
[SD_GENL_L2TP] = { .name = "l2tp", .version = 1 },
[SD_GENL_MACSEC] = { .name = "macsec", .version = 1 },
[SD_GENL_NL80211] = { .name = "nl80211", .version = 1 },
};
int sd_genl_socket_open(sd_netlink **ret) {
@ -23,12 +28,12 @@ int sd_genl_socket_open(sd_netlink **ret) {
static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id);
static int genl_message_new(sd_netlink *nl, sd_genl_family family, uint16_t nlmsg_type, uint8_t cmd, sd_netlink_message **ret) {
int r;
struct genlmsghdr *genl;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
const NLType *genl_cmd_type, *nl_type;
const NLTypeSystem *type_system;
struct genlmsghdr *genl;
size_t size;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
@ -67,21 +72,33 @@ static int genl_message_new(sd_netlink *nl, sd_genl_family family, uint16_t nlms
}
int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **ret) {
uint16_t id;
int r;
uint16_t id = GENL_ID_CTRL;
if (family != SD_GENL_ID_CTRL) {
r = lookup_id(nl, family, &id);
if (r < 0)
return r;
}
r = lookup_id(nl, family, &id);
if (r < 0)
return r;
return genl_message_new(nl, family, id, cmd, ret);
}
static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id) {
int r;
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
uint16_t u;
void *v;
int r;
if (family == SD_GENL_ID_CTRL) {
*id = GENL_ID_CTRL;
return 0;
}
v = hashmap_get(nl->genl_family_to_nlmsg_type, INT_TO_PTR(family));
if (v) {
*id = PTR_TO_UINT(v);
return 0;
}
r = sd_genl_message_new(nl, SD_GENL_ID_CTRL, CTRL_CMD_GETFAMILY, &req);
if (r < 0)
@ -95,5 +112,66 @@ static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id) {
if (r < 0)
return r;
return sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, id);
r = sd_netlink_message_read_u16(reply, CTRL_ATTR_FAMILY_ID, &u);
if (r < 0)
return r;
r = hashmap_ensure_allocated(&nl->genl_family_to_nlmsg_type, NULL);
if (r < 0)
return r;
r = hashmap_ensure_allocated(&nl->nlmsg_type_to_genl_family, NULL);
if (r < 0)
return r;
r = hashmap_put(nl->genl_family_to_nlmsg_type, INT_TO_PTR(family), UINT_TO_PTR(u));
if (r < 0)
return r;
r = hashmap_put(nl->nlmsg_type_to_genl_family, UINT_TO_PTR(u), INT_TO_PTR(family));
if (r < 0)
return r;
*id = u;
return 0;
}
int nlmsg_type_to_genl_family(sd_netlink *nl, uint16_t type, sd_genl_family *ret) {
void *p;
assert_return(nl, -EINVAL);
assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
assert(ret);
if (type == NLMSG_ERROR)
*ret = SD_GENL_ERROR;
else if (type == NLMSG_DONE)
*ret = SD_GENL_DONE;
else if (type == GENL_ID_CTRL)
*ret = SD_GENL_ID_CTRL;
else {
p = hashmap_get(nl->nlmsg_type_to_genl_family, UINT_TO_PTR(type));
if (!p)
return -EOPNOTSUPP;
*ret = PTR_TO_INT(p);
}
return 0;
}
int sd_genl_message_get_family(sd_netlink *nl, sd_netlink_message *m, sd_genl_family *family) {
uint16_t type;
int r;
assert_return(m, -EINVAL);
assert_return(nl, -EINVAL);
assert_return(nl->protocol == NETLINK_GENERIC, -EINVAL);
assert_return(family, -EINVAL);
r = sd_netlink_message_get_type(m, &type);
if (r < 0)
return r;
return nlmsg_type_to_genl_family(nl, type, family);
}

View File

@ -0,0 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include "sd-netlink.h"
int nlmsg_type_to_genl_family(sd_netlink *nl, uint16_t type, sd_genl_family *ret);

View File

@ -98,6 +98,9 @@ struct sd_netlink {
sd_event_source *time_event_source;
sd_event_source *exit_event_source;
sd_event *event;
Hashmap *genl_family_to_nlmsg_type;
Hashmap *nlmsg_type_to_genl_family;
};
struct netlink_attribute {
@ -116,8 +119,6 @@ struct netlink_container {
struct sd_netlink_message {
unsigned n_ref;
sd_netlink *rtnl;
int protocol;
struct nlmsghdr *hdr;

View File

@ -31,13 +31,15 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
buses and their queued messages. See sd-bus.
*/
m = new0(sd_netlink_message, 1);
m = new(sd_netlink_message, 1);
if (!m)
return -ENOMEM;
m->n_ref = 1;
m->protocol = rtnl->protocol;
m->sealed = false;
*m = (sd_netlink_message) {
.n_ref = 1,
.protocol = rtnl->protocol,
.sealed = false,
};
*ret = m;
@ -47,15 +49,12 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
const NLType *nl_type;
const NLTypeSystem *type_system_root;
size_t size;
int r;
assert_return(rtnl, -EINVAL);
type_system_root = type_system_get_root(rtnl->protocol);
r = type_system_get_type(type_system_root, &nl_type, type);
r = type_system_root_get_type(rtnl, &nl_type, type);
if (r < 0)
return r;
@ -616,6 +615,32 @@ int sd_netlink_message_read(sd_netlink_message *m, unsigned short type, size_t s
return r;
}
int sd_netlink_message_read_string_strdup(sd_netlink_message *m, unsigned short type, char **data) {
void *attr_data;
char *str;
int r;
assert_return(m, -EINVAL);
r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_STRING);
if (r < 0)
return r;
r = netlink_message_read_internal(m, type, &attr_data, NULL);
if (r < 0)
return r;
if (data) {
str = strndup(attr_data, r);
if (!str)
return -ENOMEM;
*data = str;
}
return 0;
}
int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data) {
int r;
void *attr_data;
@ -997,22 +1022,20 @@ int sd_netlink_message_get_errno(sd_netlink_message *m) {
return err->error;
}
int sd_netlink_message_rewind(sd_netlink_message *m) {
int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl) {
const NLType *nl_type;
const NLTypeSystem *type_system_root;
uint16_t type;
size_t size;
unsigned i;
int r;
assert_return(m, -EINVAL);
assert_return(genl || m->protocol != NETLINK_GENERIC, -EINVAL);
/* don't allow appending to message once parsed */
if (!m->sealed)
rtnl_message_seal(m);
type_system_root = type_system_get_root(m->protocol);
for (i = 1; i <= m->n_containers; i++)
m->containers[i].attributes = mfree(m->containers[i].attributes);
@ -1024,7 +1047,7 @@ int sd_netlink_message_rewind(sd_netlink_message *m) {
assert(m->hdr);
r = type_system_get_type(type_system_root, &nl_type, m->hdr->nlmsg_type);
r = type_system_root_get_type(genl, &nl_type, m->hdr->nlmsg_type);
if (r < 0)
return r;

View File

@ -313,14 +313,11 @@ int socket_read_message(sd_netlink *rtnl) {
size_t len;
int r;
unsigned i = 0;
const NLTypeSystem *type_system_root;
assert(rtnl);
assert(rtnl->rbuffer);
assert(rtnl->rbuffer_allocated >= sizeof(struct nlmsghdr));
type_system_root = type_system_get_root(rtnl->protocol);
/* read nothing, just get the pending message size */
r = socket_recv_message(rtnl->fd, &iov, NULL, true);
if (r <= 0)
@ -381,7 +378,7 @@ int socket_read_message(sd_netlink *rtnl) {
}
/* check that we support this message type */
r = type_system_get_type(type_system_root, &nl_type, new_msg->nlmsg_type);
r = type_system_root_get_type(rtnl, &nl_type, new_msg->nlmsg_type);
if (r < 0) {
if (r == -EOPNOTSUPP)
log_debug("sd-netlink: ignored message with unknown type: %i",
@ -407,7 +404,7 @@ int socket_read_message(sd_netlink *rtnl) {
return -ENOMEM;
/* seal and parse the top-level message */
r = sd_netlink_message_rewind(m);
r = sd_netlink_message_rewind(m, rtnl);
if (r < 0)
return r;

View File

@ -20,13 +20,18 @@
#include <linux/if_tunnel.h>
#include <linux/nexthop.h>
#include <linux/l2tp.h>
#include <linux/nl80211.h>
#include <linux/veth.h>
#include <linux/wireguard.h>
#include "sd-netlink.h"
#include "generic-netlink.h"
#include "hashmap.h"
#include "macro.h"
#include "missing.h"
#include "netlink-internal.h"
#include "netlink-types.h"
#include "sd-netlink.h"
#include "string-table.h"
#include "util.h"
@ -984,24 +989,60 @@ static const NLTypeSystem genl_macsec_device_type_system = {
.types = genl_macsec,
};
static const NLType genl_nl80211_types[] = {
[NL80211_ATTR_IFINDEX] = { .type = NETLINK_TYPE_U32 },
[NL80211_ATTR_MAC] = { .type = NETLINK_TYPE_ETHER_ADDR },
[NL80211_ATTR_SSID] = { .type = NETLINK_TYPE_STRING },
};
static const NLTypeSystem genl_nl80211_type_system = {
.count = ELEMENTSOF(genl_nl80211_types),
.types = genl_nl80211_types,
};
static const NLType genl_nl80211_cmds[] = {
[NL80211_CMD_GET_WIPHY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system },
[NL80211_CMD_SET_WIPHY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system },
[NL80211_CMD_NEW_WIPHY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system },
[NL80211_CMD_DEL_WIPHY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system },
[NL80211_CMD_GET_INTERFACE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system },
[NL80211_CMD_SET_INTERFACE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system },
[NL80211_CMD_NEW_INTERFACE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system },
[NL80211_CMD_DEL_INTERFACE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system },
[NL80211_CMD_GET_STATION] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system },
[NL80211_CMD_SET_STATION] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system },
[NL80211_CMD_NEW_STATION] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system },
[NL80211_CMD_DEL_STATION] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system },
};
static const NLTypeSystem genl_nl80211_cmds_type_system = {
.count = ELEMENTSOF(genl_nl80211_cmds),
.types = genl_nl80211_cmds,
};
static const NLType genl_families[] = {
[SD_GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_id_ctrl_type_system },
[SD_GENL_WIREGUARD] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_type_system },
[SD_GENL_FOU] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_fou_cmds_type_system},
[SD_GENL_FOU] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_fou_cmds_type_system },
[SD_GENL_L2TP] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_tunnel_session_type_system },
[SD_GENL_MACSEC] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_device_type_system },
[SD_GENL_NL80211] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_cmds_type_system },
};
/* Mainly used when sending message */
const NLTypeSystem genl_family_type_system_root = {
.count = ELEMENTSOF(genl_families),
.types = genl_families,
};
static const NLType genl_types[] = {
[NLMSG_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) },
[GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system, .size = sizeof(struct genlmsghdr) },
[SD_GENL_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) },
[SD_GENL_DONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system },
[SD_GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system, .size = sizeof(struct genlmsghdr) },
[SD_GENL_NL80211] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_type_system, .size = sizeof(struct genlmsghdr) },
};
/* Mainly used when message received */
const NLTypeSystem genl_type_system_root = {
.count = ELEMENTSOF(genl_types),
.types = genl_types,
@ -1049,6 +1090,31 @@ const NLTypeSystem *type_system_get_root(int protocol) {
}
}
int type_system_root_get_type(sd_netlink *nl, const NLType **ret, uint16_t type) {
sd_genl_family family;
const NLType *nl_type;
int r;
if (!nl || nl->protocol != NETLINK_GENERIC)
return type_system_get_type(&rtnl_type_system_root, ret, type);
r = nlmsg_type_to_genl_family(nl, type, &family);
if (r < 0)
return r;
if (family >= genl_type_system_root.count)
return -EOPNOTSUPP;
nl_type = &genl_type_system_root.types[family];
if (nl_type->type == NETLINK_TYPE_UNSPEC)
return -EOPNOTSUPP;
*ret = nl_type;
return 0;
}
int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type) {
const NLType *nl_type;

View File

@ -36,8 +36,6 @@ struct NLTypeSystemUnion {
const NLTypeSystem *type_systems;
};
extern const NLTypeSystem rtnl_type_system_root;
extern const NLTypeSystem genl_type_system_root;
extern const NLTypeSystem genl_family_type_system_root;
uint16_t type_get_type(const NLType *type);
@ -47,6 +45,7 @@ void type_get_type_system_union(const NLType *type, const NLTypeSystemUnion **re
const NLTypeSystem* type_system_get_root(int protocol);
uint16_t type_system_get_count(const NLTypeSystem *type_system);
int type_system_root_get_type(sd_netlink *nl, const NLType **ret, uint16_t type);
int type_system_get_type(const NLTypeSystem *type_system, const NLType **ret, uint16_t type);
int type_system_get_type_system(const NLTypeSystem *type_system, const NLTypeSystem **ret, uint16_t type);
int type_system_get_type_system_union(const NLTypeSystem *type_system, const NLTypeSystemUnion **ret, uint16_t type);

View File

@ -178,6 +178,9 @@ static sd_netlink *netlink_free(sd_netlink *rtnl) {
hashmap_free(rtnl->broadcast_group_refs);
hashmap_free(rtnl->genl_family_to_nlmsg_type);
hashmap_free(rtnl->nlmsg_type_to_genl_family);
safe_close(rtnl->fd);
return mfree(rtnl);
}

View File

@ -26,7 +26,7 @@ static void test_message_link_bridge(sd_netlink *rtnl) {
assert_se(sd_netlink_message_append_u32(message, IFLA_BRPORT_COST, 10) >= 0);
assert_se(sd_netlink_message_close_container(message) >= 0);
assert_se(sd_netlink_message_rewind(message) >= 0);
assert_se(sd_netlink_message_rewind(message, NULL) >= 0);
assert_se(sd_netlink_message_enter_container(message, IFLA_PROTINFO) >= 0);
assert_se(sd_netlink_message_read_u32(message, IFLA_BRPORT_COST, &cost) >= 0);
@ -49,7 +49,7 @@ static void test_link_configure(sd_netlink *rtnl, int ifindex) {
assert_se(sd_netlink_message_append_u32(message, IFLA_MTU, mtu) >= 0);
assert_se(sd_netlink_call(rtnl, message, 0, NULL) == 1);
assert_se(sd_netlink_message_rewind(message) >= 0);
assert_se(sd_netlink_message_rewind(message, NULL) >= 0);
assert_se(sd_netlink_message_read_string(message, IFLA_IFNAME, &name_out) >= 0);
assert_se(streq(name, name_out));
@ -153,7 +153,7 @@ static void test_route(sd_netlink *rtnl) {
return;
}
assert_se(sd_netlink_message_rewind(req) >= 0);
assert_se(sd_netlink_message_rewind(req, NULL) >= 0);
assert_se(sd_netlink_message_read_in_addr(req, RTA_GATEWAY, &addr_data) >= 0);
assert_se(addr_data.s_addr == addr.s_addr);
@ -439,7 +439,7 @@ static void test_container(sd_netlink *rtnl) {
assert_se(sd_netlink_message_close_container(m) >= 0);
assert_se(sd_netlink_message_close_container(m) == -EINVAL);
assert_se(sd_netlink_message_rewind(m) >= 0);
assert_se(sd_netlink_message_rewind(m, NULL) >= 0);
assert_se(sd_netlink_message_enter_container(m, IFLA_LINKINFO) >= 0);
assert_se(sd_netlink_message_read_string(m, IFLA_INFO_KIND, &string_data) >= 0);
@ -530,7 +530,7 @@ static void test_array(void) {
assert_se(sd_netlink_message_close_container(m) >= 0);
rtnl_message_seal(m);
assert_se(sd_netlink_message_rewind(m) >= 0);
assert_se(sd_netlink_message_rewind(m, genl) >= 0);
assert_se(sd_netlink_message_enter_container(m, CTRL_ATTR_MCAST_GROUPS) >= 0);
for (unsigned i = 0; i < 10; i++) {

View File

@ -103,6 +103,8 @@ sources = files('''
networkd-speed-meter.h
networkd-util.c
networkd-util.h
networkd-wifi.c
networkd-wifi.h
'''.split())
systemd_networkd_sources = files('networkd.c')

View File

@ -33,6 +33,7 @@
#include "networkd-neighbor.h"
#include "networkd-radv.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-wifi.h"
#include "set.h"
#include "socket-util.h"
#include "stdio-util.h"
@ -661,6 +662,25 @@ void link_dns_settings_clear(Link *link) {
link->dnssec_negative_trust_anchors = set_free_free(link->dnssec_negative_trust_anchors);
}
static void link_free_engines(Link *link) {
if (!link)
return;
link->dhcp_server = sd_dhcp_server_unref(link->dhcp_server);
link->dhcp_client = sd_dhcp_client_unref(link->dhcp_client);
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
link->dhcp_routes = set_free(link->dhcp_routes);
link->lldp = sd_lldp_unref(link->lldp);
ndisc_flush(link);
link->ipv4ll = sd_ipv4ll_unref(link->ipv4ll);
link->dhcp6_client = sd_dhcp6_client_unref(link->dhcp6_client);
link->ndisc = sd_ndisc_unref(link->ndisc);
link->radv = sd_radv_unref(link->radv);
}
static Link *link_free(Link *link) {
Address *address;
@ -686,27 +706,14 @@ static Link *link_free(Link *link) {
address_free(address);
}
sd_dhcp_server_unref(link->dhcp_server);
sd_dhcp_client_unref(link->dhcp_client);
sd_dhcp_lease_unref(link->dhcp_lease);
set_free(link->dhcp_routes);
link_lldp_emit_stop(link);
link_free_engines(link);
free(link->lease_file);
sd_lldp_unref(link->lldp);
free(link->lldp_file);
ndisc_flush(link);
sd_ipv4ll_unref(link->ipv4ll);
sd_dhcp6_client_unref(link->dhcp6_client);
sd_ndisc_unref(link->ndisc);
sd_radv_unref(link->radv);
free(link->ifname);
free(link->kind);
free(link->ssid);
(void) unlink(link->state_file);
free(link->state_file);
@ -2850,6 +2857,78 @@ static int link_configure_duid(Link *link) {
return 0;
}
int link_reconfigure(Link *link) {
Network *network;
int r;
if (IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_LINGER))
return 0;
r = network_get(link->manager, link->sd_device, link->ifname,
&link->mac, link->ssid, &link->bssid, &network);
if (r == -ENOENT) {
link_enter_unmanaged(link);
return 0;
} else if (r == 0 && network->unmanaged) {
link_enter_unmanaged(link);
return 0;
} else if (r < 0)
return r;
if (link->network == network)
return 0;
log_link_info(link, "Re-configuring with %s", network->filename);
/* Dropping old .network file */
r = link_stop_clients(link, false);
if (r < 0) {
link_enter_failed(link);
return r;
}
if (link_dhcp4_server_enabled(link))
(void) sd_dhcp_server_stop(link->dhcp_server);
r = link_drop_config(link);
if (r < 0)
return r;
if (!IN_SET(link->state, LINK_STATE_UNMANAGED, LINK_STATE_PENDING)) {
log_link_debug(link, "State is %s, dropping config", link_state_to_string(link->state));
r = link_drop_foreign_config(link);
if (r < 0)
return r;
}
link_free_carrier_maps(link);
link_free_engines(link);
link->network = network_unref(link->network);
/* Then, apply new .network file */
r = network_apply(network, link);
if (r < 0)
return r;
r = link_new_carrier_maps(link);
if (r < 0)
return r;
link_set_state(link, LINK_STATE_INITIALIZED);
/* link_configure_duid() returns 0 if it requests product UUID. In that case,
* link_configure() is called later asynchronously. */
r = link_configure_duid(link);
if (r <= 0)
return r;
r = link_configure(link);
if (r < 0)
return r;
return 0;
}
static int link_initialized_and_synced(Link *link) {
Network *network;
int r;
@ -2875,8 +2954,12 @@ static int link_initialized_and_synced(Link *link) {
return r;
if (!link->network) {
r = wifi_get_info(link);
if (r < 0)
return r;
r = network_get(link->manager, link->sd_device, link->ifname,
&link->mac, &network);
&link->mac, link->ssid, &link->bssid, &network);
if (r == -ENOENT) {
link_enter_unmanaged(link);
return 0;
@ -3250,6 +3333,15 @@ static int link_carrier_gained(Link *link) {
assert(link);
r = wifi_get_info(link);
if (r < 0)
return r;
if (r > 0) {
r = link_reconfigure(link);
if (r < 0)
return r;
}
if (IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) {
r = link_acquire_conf(link);
if (r < 0) {

View File

@ -55,6 +55,10 @@ typedef struct Link {
uint32_t mtu;
sd_device *sd_device;
/* wlan */
char *ssid;
struct ether_addr bssid;
unsigned flags;
uint8_t kernel_operstate;
@ -204,6 +208,8 @@ uint32_t link_get_ipv6_accept_ra_route_table(Link *link);
int link_request_set_routes(Link *link);
int link_request_set_nexthop(Link *link);
int link_reconfigure(Link *link);
#define ADDRESS_FMT_VAL(address) \
be32toh((address).s_addr) >> 24, \
(be32toh((address).s_addr) >> 16) & 0xFFu, \

View File

@ -29,6 +29,8 @@ Match.MACAddress, config_parse_hwaddrs,
Match.Path, config_parse_match_strv, 0, offsetof(Network, match_path)
Match.Driver, config_parse_match_strv, 0, offsetof(Network, match_driver)
Match.Type, config_parse_match_strv, 0, offsetof(Network, match_type)
Match.SSID, config_parse_match_strv, 0, offsetof(Network, match_ssid)
Match.BSSID, config_parse_hwaddrs, 0, offsetof(Network, match_bssid)
Match.Name, config_parse_match_ifnames, 0, offsetof(Network, match_name)
Match.Property, config_parse_match_property, 0, offsetof(Network, match_property)
Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, conditions)

View File

@ -159,7 +159,7 @@ int network_verify(Network *network) {
if (set_isempty(network->match_mac) && strv_isempty(network->match_path) &&
strv_isempty(network->match_driver) && strv_isempty(network->match_type) &&
strv_isempty(network->match_name) && strv_isempty(network->match_property) &&
!network->conditions)
strv_isempty(network->match_ssid) && !network->conditions)
log_warning("%s: No valid settings found in the [Match] section. "
"The file will match all interfaces. "
"If that is intended, please add Name=* in the [Match] section.",
@ -547,6 +547,8 @@ static Network *network_free(Network *network) {
strv_free(network->match_type);
strv_free(network->match_name);
strv_free(network->match_property);
strv_free(network->match_ssid);
set_free_free(network->match_bssid);
condition_free_list(network->conditions);
free(network->description);
@ -655,7 +657,7 @@ int network_get_by_name(Manager *manager, const char *name, Network **ret) {
int network_get(Manager *manager, sd_device *device,
const char *ifname, const struct ether_addr *address,
Network **ret) {
const char *ssid, const struct ether_addr *bssid, Network **ret) {
Network *network;
Iterator i;
@ -665,7 +667,8 @@ int network_get(Manager *manager, sd_device *device,
ORDERED_HASHMAP_FOREACH(network, manager->networks, i)
if (net_match_config(network->match_mac, network->match_path, network->match_driver,
network->match_type, network->match_name, network->match_property,
device, address, ifname)) {
network->match_ssid, network->match_bssid,
device, address, ifname, ssid, bssid)) {
if (network->match_name && device) {
const char *attr;
uint8_t name_assign_type = NET_NAME_UNKNOWN;

View File

@ -63,6 +63,8 @@ struct Network {
char **match_type;
char **match_name;
char **match_property;
char **match_ssid;
Set *match_bssid;
LIST_HEAD(Condition, conditions);
char *description;
@ -286,7 +288,8 @@ int network_load_one(Manager *manager, const char *filename);
int network_verify(Network *network);
int network_get_by_name(Manager *manager, const char *name, Network **ret);
int network_get(Manager *manager, sd_device *device, const char *ifname, const struct ether_addr *mac, Network **ret);
int network_get(Manager *manager, sd_device *device, const char *ifname, const struct ether_addr *mac,
const char *ssid, const struct ether_addr *bssid, Network **ret);
int network_apply(Network *network, Link *link);
void network_apply_anonymize_if_set(Network *network);

142
src/network/networkd-wifi.c Normal file
View File

@ -0,0 +1,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;
}

View File

@ -0,0 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include "sd-bus.h"
typedef struct Link Link;
int wifi_get_info(Link *link);

View File

@ -125,7 +125,7 @@ static void test_network_get(Manager *manager, sd_device *loopback) {
/* let's assume that the test machine does not have a .network file
that applies to the loopback device... */
assert_se(network_get(manager, loopback, "lo", &mac, &network) == -ENOENT);
assert_se(network_get(manager, loopback, "lo", &mac, NULL, NULL, &network) == -ENOENT);
assert_se(!network);
}

View File

@ -1103,7 +1103,8 @@ static int map_basic(sd_bus *bus, const char *member, sd_bus_message *m, unsigne
switch (type) {
case SD_BUS_TYPE_STRING: {
case SD_BUS_TYPE_STRING:
case SD_BUS_TYPE_OBJECT_PATH: {
const char **p = userdata;
const char *s;

View File

@ -35,11 +35,14 @@ typedef struct sd_netlink_message sd_netlink_message;
typedef struct sd_netlink_slot sd_netlink_slot;
typedef enum sd_gen_family {
SD_GENL_ERROR,
SD_GENL_DONE,
SD_GENL_ID_CTRL,
SD_GENL_WIREGUARD,
SD_GENL_FOU,
SD_GENL_L2TP,
SD_GENL_MACSEC,
SD_GENL_NL80211,
} sd_genl_family;
/* callback */
@ -95,6 +98,7 @@ int sd_netlink_message_open_container_union(sd_netlink_message *m, unsigned shor
int sd_netlink_message_close_container(sd_netlink_message *m);
int sd_netlink_message_read(sd_netlink_message *m, unsigned short type, size_t size, void *data);
int sd_netlink_message_read_string_strdup(sd_netlink_message *m, unsigned short type, char **data);
int sd_netlink_message_read_string(sd_netlink_message *m, unsigned short type, const char **data);
int sd_netlink_message_read_u8(sd_netlink_message *m, unsigned short type, uint8_t *data);
int sd_netlink_message_read_u16(sd_netlink_message *m, unsigned short type, uint16_t *data);
@ -110,7 +114,7 @@ int sd_netlink_message_exit_container(sd_netlink_message *m);
int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type);
int sd_netlink_message_cancel_array(sd_netlink_message *m);
int sd_netlink_message_rewind(sd_netlink_message *m);
int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl);
sd_netlink_message *sd_netlink_message_next(sd_netlink_message *m);
@ -201,6 +205,7 @@ int sd_rtnl_message_routing_policy_rule_get_flags(sd_netlink_message *m, unsigne
/* genl */
int sd_genl_socket_open(sd_netlink **nl);
int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **m);
int sd_genl_message_get_family(sd_netlink *nl, sd_netlink_message *m, sd_genl_family *family);
/* slot */
sd_netlink_slot *sd_netlink_slot_ref(sd_netlink_slot *nl);

View File

@ -242,8 +242,8 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret)
LIST_FOREACH(links, link, ctx->links) {
if (net_match_config(link->match_mac, link->match_path, link->match_driver,
link->match_type, link->match_name, link->match_property,
device, NULL, NULL)) {
link->match_type, link->match_name, link->match_property, NULL, NULL,
device, NULL, NULL, NULL, NULL)) {
if (link->match_name && !strv_contains(link->match_name, "*")) {
unsigned name_assign_type = NET_NAME_UNKNOWN;

View File

@ -19,6 +19,8 @@ Type=
Driver=
Architecture=
Path=
SSID=
BSSID=
Name=
Property=
Virtualization=