mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
Merge pull request #22502 from yuwata/udev-net-virtual-wlan-interface
network: add virtual wlan interface support
This commit is contained in:
@@ -192,6 +192,9 @@
|
||||
|
||||
<row><entry><varname>ipoib</varname></entry>
|
||||
<entry>An IP over Infiniband subinterface.</entry></row>
|
||||
|
||||
<row><entry><varname>virtual-wlan</varname></entry>
|
||||
<entry>A virtual local wireless network (WLAN) interface.</entry></row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
@@ -2179,6 +2182,43 @@
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>[VirtualWLAN] Section Options</title>
|
||||
<para>The [VirtualWLAN] section only applies to virtual WLAN interfaces, and accepts the following
|
||||
keys:</para>
|
||||
|
||||
<variablelist class='network-directives'>
|
||||
<varlistentry>
|
||||
<term><varname>PhysicalDevice=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the name or index of the WLAN physical WLAN device (e.g. <literal>0</literal>
|
||||
or <literal>phy0</literal>). The list of the physical WLAN devices that exist os the host can
|
||||
be obtained by <command>iw phy</command> command. This option is mandatory.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Type=</varname></term>
|
||||
<listitem>
|
||||
<para>Specifies the type of the interface. Takes one of the <literal>ad-hoc</literal>,
|
||||
<literal>station</literal>, <literal>ap</literal>, <literal>ap-vlan</literal>,
|
||||
<literal>wds</literal>, <literal>monitor</literal>, <literal>mesh-point</literal>,
|
||||
<literal>p2p-client</literal>, <literal>p2p-go</literal>, <literal>p2p-device</literal>,
|
||||
<literal>ocb</literal>, and <literal>nan</literal>. This option is mandatory.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>WDS=</varname></term>
|
||||
<listitem>
|
||||
<para>Enables the Wireless Distribution System (WDS) mode on the interface. The mode is also
|
||||
known as the <literal>4 address mode</literal>. Takes a boolean value. Defaults to unset, and
|
||||
the kernel's default will be used.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Examples</title>
|
||||
<example>
|
||||
|
||||
@@ -11,18 +11,26 @@ sources = files('''
|
||||
netdev/bridge.h
|
||||
netdev/dummy.c
|
||||
netdev/dummy.h
|
||||
netdev/fou-tunnel.c
|
||||
netdev/fou-tunnel.h
|
||||
netdev/ifb.c
|
||||
netdev/ifb.h
|
||||
netdev/ipoib.c
|
||||
netdev/ipoib.h
|
||||
netdev/ipvlan.c
|
||||
netdev/ipvlan.h
|
||||
netdev/l2tp-tunnel.c
|
||||
netdev/l2tp-tunnel.h
|
||||
netdev/macsec.c
|
||||
netdev/macsec.h
|
||||
netdev/macvlan.c
|
||||
netdev/macvlan.h
|
||||
netdev/netdev.c
|
||||
netdev/netdev-util.c
|
||||
netdev/netdev-util.h
|
||||
netdev/netdev.c
|
||||
netdev/netdev.h
|
||||
netdev/netdevsim.c
|
||||
netdev/netdevsim.h
|
||||
netdev/nlmon.c
|
||||
netdev/nlmon.h
|
||||
netdev/tunnel.c
|
||||
@@ -45,14 +53,8 @@ sources = files('''
|
||||
netdev/vxcan.h
|
||||
netdev/wireguard.c
|
||||
netdev/wireguard.h
|
||||
netdev/netdevsim.c
|
||||
netdev/netdevsim.h
|
||||
netdev/fou-tunnel.c
|
||||
netdev/fou-tunnel.h
|
||||
netdev/l2tp-tunnel.c
|
||||
netdev/l2tp-tunnel.h
|
||||
netdev/macsec.c
|
||||
netdev/macsec.h
|
||||
netdev/wlan.c
|
||||
netdev/wlan.h
|
||||
netdev/xfrm.c
|
||||
netdev/xfrm.h
|
||||
networkd-address-generation.c
|
||||
@@ -143,6 +145,8 @@ sources = files('''
|
||||
networkd-util.h
|
||||
networkd-wifi.c
|
||||
networkd-wifi.h
|
||||
networkd-wiphy.c
|
||||
networkd-wiphy.h
|
||||
tc/cake.c
|
||||
tc/cake.h
|
||||
tc/codel.c
|
||||
|
||||
@@ -27,6 +27,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
|
||||
#include "vxcan.h"
|
||||
#include "vxlan.h"
|
||||
#include "wireguard.h"
|
||||
#include "wlan.h"
|
||||
#include "xfrm.h"
|
||||
%}
|
||||
struct ConfigPerfItem;
|
||||
@@ -258,3 +259,6 @@ BatmanAdvanced.RoutingAlgorithm, config_parse_batadv_routing_algorithm,
|
||||
IPoIB.PartitionKey, config_parse_ipoib_pkey, 0, offsetof(IPoIB, pkey)
|
||||
IPoIB.Mode, config_parse_ipoib_mode, 0, offsetof(IPoIB, mode)
|
||||
IPoIB.IgnoreUserspaceMulticastGroups, config_parse_tristate, 0, offsetof(IPoIB, umcast)
|
||||
VirtualWLAN.PhysicalDevice, config_parse_wiphy, 0, 0
|
||||
VirtualWLAN.Type, config_parse_wlan_iftype, 0, offsetof(WLan, iftype)
|
||||
VirtualWLAN.WDS, config_parse_tristate, 0, offsetof(WLan, wds)
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "vxcan.h"
|
||||
#include "vxlan.h"
|
||||
#include "wireguard.h"
|
||||
#include "wlan.h"
|
||||
#include "xfrm.h"
|
||||
|
||||
const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
|
||||
@@ -86,6 +87,7 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
|
||||
[NETDEV_KIND_VXCAN] = &vxcan_vtable,
|
||||
[NETDEV_KIND_VXLAN] = &vxlan_vtable,
|
||||
[NETDEV_KIND_WIREGUARD] = &wireguard_vtable,
|
||||
[NETDEV_KIND_WLAN] = &wlan_vtable,
|
||||
[NETDEV_KIND_XFRM] = &xfrm_vtable,
|
||||
};
|
||||
|
||||
@@ -126,6 +128,7 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
|
||||
[NETDEV_KIND_VXCAN] = "vxcan",
|
||||
[NETDEV_KIND_VXLAN] = "vxlan",
|
||||
[NETDEV_KIND_WIREGUARD] = "wireguard",
|
||||
[NETDEV_KIND_WLAN] = "virtual-wlan",
|
||||
[NETDEV_KIND_XFRM] = "xfrm",
|
||||
};
|
||||
|
||||
@@ -352,37 +355,40 @@ int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *message) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_enter_container(message, IFLA_LINKINFO);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not get LINKINFO: %m");
|
||||
if (!NETDEV_VTABLE(netdev)->skip_netdev_kind_check) {
|
||||
|
||||
r = sd_netlink_message_read_string(message, IFLA_INFO_KIND, &received_kind);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not get KIND: %m");
|
||||
r = sd_netlink_message_enter_container(message, IFLA_LINKINFO);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not get LINKINFO: %m");
|
||||
|
||||
r = sd_netlink_message_exit_container(message);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not exit container: %m");
|
||||
r = sd_netlink_message_read_string(message, IFLA_INFO_KIND, &received_kind);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not get KIND: %m");
|
||||
|
||||
if (netdev->kind == NETDEV_KIND_TAP)
|
||||
/* the kernel does not distinguish between tun and tap */
|
||||
kind = "tun";
|
||||
else {
|
||||
kind = netdev_kind_to_string(netdev->kind);
|
||||
if (!kind) {
|
||||
log_netdev_error(netdev, "Could not get kind");
|
||||
r = sd_netlink_message_exit_container(message);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Could not exit container: %m");
|
||||
|
||||
if (netdev->kind == NETDEV_KIND_TAP)
|
||||
/* the kernel does not distinguish between tun and tap */
|
||||
kind = "tun";
|
||||
else {
|
||||
kind = netdev_kind_to_string(netdev->kind);
|
||||
if (!kind) {
|
||||
log_netdev_error(netdev, "Could not get kind");
|
||||
netdev_enter_failed(netdev);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!streq(kind, received_kind)) {
|
||||
log_netdev_error(netdev, "Received newlink with wrong KIND %s, expected %s",
|
||||
received_kind, kind);
|
||||
netdev_enter_failed(netdev);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!streq(kind, received_kind)) {
|
||||
log_netdev_error(netdev, "Received newlink with wrong KIND %s, expected %s",
|
||||
received_kind, kind);
|
||||
netdev_enter_failed(netdev);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
netdev->ifindex = ifindex;
|
||||
|
||||
log_netdev_debug(netdev, "netdev has index %d", netdev->ifindex);
|
||||
@@ -621,22 +627,23 @@ int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t callb
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool netdev_is_ready_to_create(NetDev *netdev, Link *link) {
|
||||
static int netdev_is_ready_to_create(NetDev *netdev, Link *link) {
|
||||
assert(netdev);
|
||||
assert(link);
|
||||
|
||||
if (netdev->state != NETDEV_STATE_LOADING)
|
||||
return false;
|
||||
|
||||
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
|
||||
return false;
|
||||
if (link) {
|
||||
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
|
||||
return false;
|
||||
|
||||
if (netdev_get_create_type(netdev) == NETDEV_CREATE_AFTER_CONFIGURED &&
|
||||
link->state != LINK_STATE_CONFIGURED)
|
||||
return false;
|
||||
if (netdev_get_create_type(netdev) == NETDEV_CREATE_AFTER_CONFIGURED &&
|
||||
link->state != LINK_STATE_CONFIGURED)
|
||||
return false;
|
||||
|
||||
if (link->set_link_messages > 0)
|
||||
return false;
|
||||
if (link->set_link_messages > 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NETDEV_VTABLE(netdev)->is_ready_to_create)
|
||||
return NETDEV_VTABLE(netdev)->is_ready_to_create(netdev, link);
|
||||
@@ -649,12 +656,13 @@ int request_process_stacked_netdev(Request *req) {
|
||||
|
||||
assert(req);
|
||||
assert(req->link);
|
||||
assert(req->type == REQUEST_TYPE_STACKED_NETDEV);
|
||||
assert(req->type == REQUEST_TYPE_NETDEV_STACKED);
|
||||
assert(req->netdev);
|
||||
assert(req->netlink_handler);
|
||||
|
||||
if (!netdev_is_ready_to_create(req->netdev, req->link))
|
||||
return 0;
|
||||
r = netdev_is_ready_to_create(req->netdev, req->link);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
r = netdev_join(req->netdev, req->link, req->netlink_handler);
|
||||
if (r < 0)
|
||||
@@ -731,13 +739,13 @@ int link_request_stacked_netdev(Link *link, NetDev *netdev) {
|
||||
|
||||
if (netdev_get_create_type(netdev) == NETDEV_CREATE_STACKED) {
|
||||
link->stacked_netdevs_created = false;
|
||||
r = link_queue_request(link, REQUEST_TYPE_STACKED_NETDEV, netdev, false,
|
||||
r = link_queue_request(link, REQUEST_TYPE_NETDEV_STACKED, netdev_ref(netdev), true,
|
||||
&link->create_stacked_netdev_messages,
|
||||
link_create_stacked_netdev_handler,
|
||||
NULL);
|
||||
} else {
|
||||
link->stacked_netdevs_after_configured_created = false;
|
||||
r = link_queue_request(link, REQUEST_TYPE_STACKED_NETDEV, netdev, false,
|
||||
r = link_queue_request(link, REQUEST_TYPE_NETDEV_STACKED, netdev_ref(netdev), true,
|
||||
&link->create_stacked_netdev_after_configured_messages,
|
||||
link_create_stacked_netdev_after_configured_handler,
|
||||
NULL);
|
||||
@@ -750,6 +758,44 @@ int link_request_stacked_netdev(Link *link, NetDev *netdev) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int request_process_independent_netdev(Request *req) {
|
||||
int r;
|
||||
|
||||
assert(req);
|
||||
assert(req->type == REQUEST_TYPE_NETDEV_INDEPENDENT);
|
||||
assert(req->netdev);
|
||||
|
||||
r = netdev_is_ready_to_create(req->netdev, NULL);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
r = netdev_create(req->netdev, NULL, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int netdev_request(NetDev *netdev) {
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
|
||||
if (!IN_SET(netdev_get_create_type(netdev), NETDEV_CREATE_MASTER, NETDEV_CREATE_INDEPENDENT) &&
|
||||
!netdev_is_stacked_and_independent(netdev))
|
||||
return 0;
|
||||
|
||||
r = netdev_is_ready_to_create(netdev, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
/* If the netdev has no dependency, then create it now. */
|
||||
return netdev_create(netdev, NULL, NULL);
|
||||
|
||||
/* Otherwise, wait for the dependencies being resolved. */
|
||||
return netdev_queue_request(netdev, NULL);
|
||||
}
|
||||
|
||||
int netdev_load_one(Manager *manager, const char *filename) {
|
||||
_cleanup_(netdev_unrefp) NetDev *netdev_raw = NULL, *netdev = NULL;
|
||||
const char *dropin_dirname;
|
||||
@@ -860,20 +906,11 @@ int netdev_load_one(Manager *manager, const char *filename) {
|
||||
|
||||
log_netdev_debug(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
|
||||
|
||||
if (IN_SET(netdev_get_create_type(netdev), NETDEV_CREATE_MASTER, NETDEV_CREATE_INDEPENDENT)) {
|
||||
r = netdev_create(netdev, NULL, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (netdev_is_stacked_and_independent(netdev)) {
|
||||
r = netdev_create(netdev, NULL, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
netdev = NULL;
|
||||
r = netdev_request(netdev);
|
||||
if (r < 0)
|
||||
return log_netdev_warning_errno(netdev, r, "Failed to request to create: %m");
|
||||
|
||||
TAKE_PTR(netdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
"-VXLAN\0" \
|
||||
"-WireGuard\0" \
|
||||
"-WireGuardPeer\0" \
|
||||
"-VirtualWLAN\0" \
|
||||
"-Xfrm\0"
|
||||
|
||||
typedef enum NetDevKind {
|
||||
@@ -82,6 +83,7 @@ typedef enum NetDevKind {
|
||||
NETDEV_KIND_VXCAN,
|
||||
NETDEV_KIND_VXLAN,
|
||||
NETDEV_KIND_WIREGUARD,
|
||||
NETDEV_KIND_WLAN,
|
||||
NETDEV_KIND_XFRM,
|
||||
_NETDEV_KIND_MAX,
|
||||
_NETDEV_KIND_TUNNEL, /* Used by config_parse_stacked_netdev() */
|
||||
@@ -173,6 +175,9 @@ typedef struct NetDevVTable {
|
||||
|
||||
/* Generate MAC address when MACAddress= is not specified. */
|
||||
bool generate_mac;
|
||||
|
||||
/* When assigning ifindex to the netdev, skip to check if the netdev kind matches. */
|
||||
bool skip_netdev_kind_check;
|
||||
} NetDevVTable;
|
||||
|
||||
extern const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX];
|
||||
@@ -210,6 +215,7 @@ int netdev_generate_hw_addr(NetDev *netdev, Link *link, const char *name,
|
||||
const struct hw_addr_data *hw_addr, struct hw_addr_data *ret);
|
||||
int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t cb);
|
||||
|
||||
int request_process_independent_netdev(Request *req);
|
||||
int request_process_stacked_netdev(Request *req);
|
||||
int link_request_stacked_netdev(Link *link, NetDev *netdev);
|
||||
|
||||
|
||||
@@ -657,12 +657,14 @@ static int netdev_tunnel_is_ready_to_create(NetDev *netdev, Link *link) {
|
||||
Tunnel *t;
|
||||
|
||||
assert(netdev);
|
||||
assert(link);
|
||||
|
||||
t = TUNNEL(netdev);
|
||||
|
||||
assert(t);
|
||||
|
||||
if (t->independent)
|
||||
return true;
|
||||
|
||||
return tunnel_get_local_address(t, link, NULL) >= 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -427,12 +427,14 @@ static int netdev_vxlan_is_ready_to_create(NetDev *netdev, Link *link) {
|
||||
VxLan *v;
|
||||
|
||||
assert(netdev);
|
||||
assert(link);
|
||||
|
||||
v = VXLAN(netdev);
|
||||
|
||||
assert(v);
|
||||
|
||||
if (v->independent)
|
||||
return true;
|
||||
|
||||
return vxlan_get_local_address(v, link, NULL, NULL) >= 0;
|
||||
}
|
||||
|
||||
|
||||
260
src/network/netdev/wlan.c
Normal file
260
src/network/netdev/wlan.c
Normal file
@@ -0,0 +1,260 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#include "sd-netlink.h"
|
||||
|
||||
#include "netlink-util.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-wiphy.h"
|
||||
#include "parse-util.h"
|
||||
#include "wifi-util.h"
|
||||
#include "wlan.h"
|
||||
|
||||
static void wlan_done(NetDev *netdev) {
|
||||
WLan *w;
|
||||
|
||||
assert(netdev);
|
||||
|
||||
w = WLAN(netdev);
|
||||
|
||||
assert(w);
|
||||
|
||||
w->wiphy_name = mfree(w->wiphy_name);
|
||||
}
|
||||
|
||||
static void wlan_init(NetDev *netdev) {
|
||||
WLan *w;
|
||||
|
||||
assert(netdev);
|
||||
|
||||
w = WLAN(netdev);
|
||||
|
||||
assert(w);
|
||||
|
||||
w->wiphy_index = UINT32_MAX;
|
||||
w->wds = -1;
|
||||
}
|
||||
|
||||
static int wlan_get_wiphy(NetDev *netdev, Wiphy **ret) {
|
||||
WLan *w;
|
||||
|
||||
assert(netdev);
|
||||
|
||||
w = WLAN(netdev);
|
||||
|
||||
assert(w);
|
||||
|
||||
if (w->wiphy_name)
|
||||
return wiphy_get_by_name(netdev->manager, w->wiphy_name, ret);
|
||||
|
||||
return wiphy_get_by_index(netdev->manager, w->wiphy_index, ret);
|
||||
}
|
||||
|
||||
static int wlan_is_ready_to_create(NetDev *netdev, Link *link) {
|
||||
return wlan_get_wiphy(netdev, NULL) >= 0;
|
||||
}
|
||||
|
||||
static int wlan_fill_message(NetDev *netdev, sd_netlink_message *m) {
|
||||
Wiphy *wiphy;
|
||||
WLan *w;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(m);
|
||||
|
||||
w = WLAN(netdev);
|
||||
|
||||
assert(w);
|
||||
|
||||
r = wlan_get_wiphy(netdev, &wiphy);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_append_u32(m, NL80211_ATTR_WIPHY, wiphy->index);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_append_string(m, NL80211_ATTR_IFNAME, netdev->ifname);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_netlink_message_append_u32(m, NL80211_ATTR_IFTYPE, w->iftype);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!hw_addr_is_null(&netdev->hw_addr) && netdev->hw_addr.length == ETH_ALEN) {
|
||||
r = sd_netlink_message_append_ether_addr(m, NL80211_ATTR_MAC, &netdev->hw_addr.ether);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (w->wds >= 0) {
|
||||
r = sd_netlink_message_append_u8(m, NL80211_ATTR_4ADDR, w->wds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wlan_create_handler(sd_netlink *genl, sd_netlink_message *m, NetDev *netdev) {
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(netdev->state != _NETDEV_STATE_INVALID);
|
||||
|
||||
r = sd_netlink_message_get_errno(m);
|
||||
if (IN_SET(r, -EEXIST, -ENFILE))
|
||||
/* Unlike the other netdevs, the kernel may return -ENFILE. See dev_alloc_name(). */
|
||||
log_netdev_info(netdev, "WLAN interface exists, using existing without changing its parameters.");
|
||||
else if (r < 0) {
|
||||
log_netdev_warning_errno(netdev, r, "WLAN interface could not be created: %m");
|
||||
netdev_enter_failed(netdev);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
log_netdev_debug(netdev, "WLAN interface is created.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int wlan_create(NetDev *netdev) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(netdev->manager);
|
||||
assert(netdev->manager->genl);
|
||||
|
||||
r = sd_genl_message_new(netdev->manager->genl, NL80211_GENL_NAME, NL80211_CMD_NEW_INTERFACE, &m);
|
||||
if (r < 0)
|
||||
return log_netdev_warning_errno(netdev, r, "Failed to allocate netlink message: %m");
|
||||
|
||||
r = wlan_fill_message(netdev, m);
|
||||
if (r < 0)
|
||||
return log_netdev_warning_errno(netdev, r, "Failed to fill netlink message: %m");
|
||||
|
||||
r = netlink_call_async(netdev->manager->genl, NULL, m, wlan_create_handler,
|
||||
netdev_destroy_callback, netdev);
|
||||
if (r < 0)
|
||||
return log_netdev_warning_errno(netdev, r, "Failed to send netlink message: %m");
|
||||
|
||||
netdev_ref(netdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wlan_verify(NetDev *netdev, const char *filename) {
|
||||
WLan *w;
|
||||
|
||||
assert(netdev);
|
||||
assert(filename);
|
||||
|
||||
w = WLAN(netdev);
|
||||
|
||||
assert(w);
|
||||
|
||||
if (w->iftype == NL80211_IFTYPE_UNSPECIFIED)
|
||||
return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: WLAN interface type is not specified, ignoring.",
|
||||
filename);
|
||||
|
||||
if (w->wiphy_index == UINT32_MAX && isempty(w->wiphy_name))
|
||||
return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
|
||||
"%s: physical WLAN device is not specified, ignoring.",
|
||||
filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_wiphy(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
WLan *w = userdata;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(userdata);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
w->wiphy_name = mfree(w->wiphy_name);
|
||||
w->wiphy_index = UINT32_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = safe_atou32(rvalue, &w->wiphy_index);
|
||||
if (r >= 0) {
|
||||
w->wiphy_name = mfree(w->wiphy_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = free_and_strdup_warn(&w->wiphy_name, rvalue);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
w->wiphy_index = UINT32_MAX;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_wlan_iftype(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
enum nl80211_iftype t, *iftype = data;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
*iftype = NL80211_IFTYPE_UNSPECIFIED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
t = nl80211_iftype_from_string(rvalue);
|
||||
/* We reuse the kernel provided enum which does not contain negative value. So, the cast
|
||||
* below is mandatory. Otherwise, the check below always passes. */
|
||||
if ((int) t < 0) {
|
||||
log_syntax(unit, LOG_WARNING, filename, line, t,
|
||||
"Failed to parse wlan interface type, ignoring assignment: %s",
|
||||
rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*iftype = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const NetDevVTable wlan_vtable = {
|
||||
.object_size = sizeof(WLan),
|
||||
.init = wlan_init,
|
||||
.done = wlan_done,
|
||||
.sections = NETDEV_COMMON_SECTIONS "VirtualWLAN\0",
|
||||
.is_ready_to_create = wlan_is_ready_to_create,
|
||||
.create = wlan_create,
|
||||
.create_type = NETDEV_CREATE_INDEPENDENT,
|
||||
.config_verify = wlan_verify,
|
||||
.iftype = ARPHRD_ETHER,
|
||||
.generate_mac = true,
|
||||
.skip_netdev_kind_check = true,
|
||||
};
|
||||
22
src/network/netdev/wlan.h
Normal file
22
src/network/netdev/wlan.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <linux/nl80211.h>
|
||||
|
||||
#include "conf-parser.h"
|
||||
#include "netdev.h"
|
||||
|
||||
typedef struct WLan {
|
||||
NetDev meta;
|
||||
|
||||
char *wiphy_name;
|
||||
uint32_t wiphy_index;
|
||||
enum nl80211_iftype iftype;
|
||||
int wds; /* tristate */
|
||||
} WLan;
|
||||
|
||||
DEFINE_NETDEV_CAST(WLAN, WLan);
|
||||
extern const NetDevVTable wlan_vtable;
|
||||
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_wiphy);
|
||||
CONFIG_PARSER_PROTOTYPE(config_parse_wlan_iftype);
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "networkd-speed-meter.h"
|
||||
#include "networkd-state-file.h"
|
||||
#include "networkd-wifi.h"
|
||||
#include "networkd-wiphy.h"
|
||||
#include "ordered-set.h"
|
||||
#include "path-lookup.h"
|
||||
#include "path-util.h"
|
||||
@@ -554,6 +555,9 @@ Manager* manager_free(Manager *m) {
|
||||
|
||||
m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref);
|
||||
|
||||
m->wiphy_by_name = hashmap_free(m->wiphy_by_name);
|
||||
m->wiphy_by_index = hashmap_free_with_destructor(m->wiphy_by_index, wiphy_free);
|
||||
|
||||
ordered_set_free_free(m->address_pools);
|
||||
|
||||
hashmap_free(m->route_table_names_by_number);
|
||||
@@ -793,6 +797,20 @@ static int manager_enumerate_nexthop(Manager *m) {
|
||||
return manager_enumerate_internal(m, m->rtnl, req, manager_rtnl_process_nexthop);
|
||||
}
|
||||
|
||||
static int manager_enumerate_nl80211_wiphy(Manager *m) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(m->genl);
|
||||
|
||||
r = sd_genl_message_new(m->genl, NL80211_GENL_NAME, NL80211_CMD_GET_WIPHY, &req);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return manager_enumerate_internal(m, m->genl, req, manager_genl_process_nl80211_wiphy);
|
||||
}
|
||||
|
||||
static int manager_enumerate_nl80211_config(Manager *m) {
|
||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
|
||||
int r;
|
||||
@@ -878,6 +896,12 @@ int manager_enumerate(Manager *m) {
|
||||
else if (r < 0)
|
||||
return log_error_errno(r, "Could not enumerate routing policy rules: %m");
|
||||
|
||||
r = manager_enumerate_nl80211_wiphy(m);
|
||||
if (r == -EOPNOTSUPP)
|
||||
log_debug_errno(r, "Could not enumerate wireless LAN phy, ignoring: %m");
|
||||
else if (r < 0)
|
||||
return log_error_errno(r, "Could not enumerate wireless LAN phy: %m");
|
||||
|
||||
r = manager_enumerate_nl80211_config(m);
|
||||
if (r == -EOPNOTSUPP)
|
||||
log_debug_errno(r, "Could not enumerate wireless LAN interfaces, ignoring: %m");
|
||||
|
||||
@@ -84,6 +84,10 @@ struct Manager {
|
||||
Hashmap *route_table_numbers_by_name;
|
||||
Hashmap *route_table_names_by_number;
|
||||
|
||||
/* Wiphy */
|
||||
Hashmap *wiphy_by_index;
|
||||
Hashmap *wiphy_by_name;
|
||||
|
||||
/* For link speed meter */
|
||||
bool use_speed_meter;
|
||||
sd_event_source *speed_meter_event_source;
|
||||
|
||||
@@ -46,6 +46,10 @@ static void request_free_object(RequestType type, void *object) {
|
||||
case REQUEST_TYPE_NEIGHBOR:
|
||||
neighbor_free(object);
|
||||
break;
|
||||
case REQUEST_TYPE_NETDEV_INDEPENDENT:
|
||||
case REQUEST_TYPE_NETDEV_STACKED:
|
||||
netdev_unref(object);
|
||||
break;
|
||||
case REQUEST_TYPE_NEXTHOP:
|
||||
nexthop_free(object);
|
||||
break;
|
||||
@@ -58,7 +62,6 @@ static void request_free_object(RequestType type, void *object) {
|
||||
routing_policy_rule_free(object);
|
||||
break;
|
||||
case REQUEST_TYPE_SET_LINK:
|
||||
case REQUEST_TYPE_STACKED_NETDEV:
|
||||
break;
|
||||
case REQUEST_TYPE_TRAFFIC_CONTROL:
|
||||
traffic_control_free(object);
|
||||
@@ -99,10 +102,12 @@ void request_drop(Request *req) {
|
||||
|
||||
static void request_hash_func(const Request *req, struct siphash *state) {
|
||||
assert(req);
|
||||
assert(req->link);
|
||||
assert(state);
|
||||
|
||||
siphash24_compress(&req->link->ifindex, sizeof(req->link->ifindex), state);
|
||||
siphash24_compress_boolean(req->link, state);
|
||||
if (req->link)
|
||||
siphash24_compress(&req->link->ifindex, sizeof(req->link->ifindex), state);
|
||||
|
||||
siphash24_compress(&req->type, sizeof(req->type), state);
|
||||
|
||||
switch (req->type) {
|
||||
@@ -114,7 +119,8 @@ static void request_hash_func(const Request *req, struct siphash *state) {
|
||||
case REQUEST_TYPE_ADDRESS_LABEL:
|
||||
case REQUEST_TYPE_BRIDGE_FDB:
|
||||
case REQUEST_TYPE_BRIDGE_MDB:
|
||||
case REQUEST_TYPE_STACKED_NETDEV:
|
||||
case REQUEST_TYPE_NETDEV_INDEPENDENT:
|
||||
case REQUEST_TYPE_NETDEV_STACKED:
|
||||
/* TODO: Currently, these types do not have any specific hash and compare functions.
|
||||
* Fortunately, all these objects are 'static', thus we can use the trivial functions. */
|
||||
trivial_hash_func(req->object, state);
|
||||
@@ -163,13 +169,17 @@ static int request_compare_func(const struct Request *a, const struct Request *b
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(a->link);
|
||||
assert(b->link);
|
||||
|
||||
r = CMP(a->link->ifindex, b->link->ifindex);
|
||||
r = CMP(!!a->link, !!b->link);
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
if (a->link) {
|
||||
r = CMP(a->link->ifindex, b->link->ifindex);
|
||||
if (r != 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = CMP(a->type, b->type);
|
||||
if (r != 0)
|
||||
return r;
|
||||
@@ -182,7 +192,8 @@ static int request_compare_func(const struct Request *a, const struct Request *b
|
||||
case REQUEST_TYPE_ADDRESS_LABEL:
|
||||
case REQUEST_TYPE_BRIDGE_FDB:
|
||||
case REQUEST_TYPE_BRIDGE_MDB:
|
||||
case REQUEST_TYPE_STACKED_NETDEV:
|
||||
case REQUEST_TYPE_NETDEV_INDEPENDENT:
|
||||
case REQUEST_TYPE_NETDEV_STACKED:
|
||||
return trivial_compare_func(a->object, b->object);
|
||||
case REQUEST_TYPE_DHCP_SERVER:
|
||||
case REQUEST_TYPE_DHCP4_CLIENT:
|
||||
@@ -220,6 +231,48 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
|
||||
request_compare_func,
|
||||
request_free);
|
||||
|
||||
int netdev_queue_request(
|
||||
NetDev *netdev,
|
||||
Request **ret) {
|
||||
|
||||
_cleanup_(request_freep) Request *req = NULL;
|
||||
Request *existing;
|
||||
int r;
|
||||
|
||||
assert(netdev);
|
||||
assert(netdev->manager);
|
||||
|
||||
req = new(Request, 1);
|
||||
if (!req)
|
||||
return -ENOMEM;
|
||||
|
||||
*req = (Request) {
|
||||
.netdev = netdev_ref(netdev),
|
||||
.type = REQUEST_TYPE_NETDEV_INDEPENDENT,
|
||||
.consume_object = true,
|
||||
};
|
||||
|
||||
existing = ordered_set_get(netdev->manager->request_queue, req);
|
||||
if (existing) {
|
||||
/* To prevent from removing the existing request. */
|
||||
req->netdev = netdev_unref(req->netdev);
|
||||
|
||||
if (ret)
|
||||
*ret = existing;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = ordered_set_ensure_put(&netdev->manager->request_queue, &request_hash_ops, req);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret)
|
||||
*ret = req;
|
||||
|
||||
TAKE_PTR(req);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int link_queue_request(
|
||||
Link *link,
|
||||
RequestType type,
|
||||
@@ -340,6 +393,12 @@ int manager_process_requests(sd_event_source *s, void *userdata) {
|
||||
case REQUEST_TYPE_NEIGHBOR:
|
||||
r = request_process_neighbor(req);
|
||||
break;
|
||||
case REQUEST_TYPE_NETDEV_INDEPENDENT:
|
||||
r = request_process_independent_netdev(req);
|
||||
break;
|
||||
case REQUEST_TYPE_NETDEV_STACKED:
|
||||
r = request_process_stacked_netdev(req);
|
||||
break;
|
||||
case REQUEST_TYPE_NEXTHOP:
|
||||
r = request_process_nexthop(req);
|
||||
break;
|
||||
@@ -355,9 +414,6 @@ int manager_process_requests(sd_event_source *s, void *userdata) {
|
||||
case REQUEST_TYPE_SET_LINK:
|
||||
r = request_process_set_link(req);
|
||||
break;
|
||||
case REQUEST_TYPE_STACKED_NETDEV:
|
||||
r = request_process_stacked_netdev(req);
|
||||
break;
|
||||
case REQUEST_TYPE_TRAFFIC_CONTROL:
|
||||
r = request_process_traffic_control(req);
|
||||
break;
|
||||
@@ -367,9 +423,10 @@ int manager_process_requests(sd_event_source *s, void *userdata) {
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
if (r < 0)
|
||||
link_enter_failed(req->link);
|
||||
if (r > 0) {
|
||||
if (r < 0) {
|
||||
if (req->link)
|
||||
link_enter_failed(req->link);
|
||||
} else if (r > 0) {
|
||||
ordered_set_remove(manager->request_queue, req);
|
||||
request_free(req);
|
||||
processed = true;
|
||||
|
||||
@@ -28,12 +28,13 @@ typedef enum RequestType {
|
||||
REQUEST_TYPE_IPV6_PROXY_NDP,
|
||||
REQUEST_TYPE_NDISC,
|
||||
REQUEST_TYPE_NEIGHBOR,
|
||||
REQUEST_TYPE_NETDEV_INDEPENDENT,
|
||||
REQUEST_TYPE_NETDEV_STACKED,
|
||||
REQUEST_TYPE_NEXTHOP,
|
||||
REQUEST_TYPE_RADV,
|
||||
REQUEST_TYPE_ROUTE,
|
||||
REQUEST_TYPE_ROUTING_POLICY_RULE,
|
||||
REQUEST_TYPE_SET_LINK,
|
||||
REQUEST_TYPE_STACKED_NETDEV,
|
||||
REQUEST_TYPE_TRAFFIC_CONTROL,
|
||||
REQUEST_TYPE_UP_DOWN,
|
||||
_REQUEST_TYPE_MAX,
|
||||
@@ -66,6 +67,10 @@ typedef struct Request {
|
||||
|
||||
void request_drop(Request *req);
|
||||
|
||||
int netdev_queue_request(
|
||||
NetDev *netdev,
|
||||
Request **ret);
|
||||
|
||||
int link_queue_request(
|
||||
Link *link,
|
||||
RequestType type,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "networkd-link.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-wifi.h"
|
||||
#include "networkd-wiphy.h"
|
||||
#include "string-util.h"
|
||||
#include "wifi-util.h"
|
||||
|
||||
@@ -72,6 +73,8 @@ int manager_genl_process_nl80211_config(sd_netlink *genl, sd_netlink_message *me
|
||||
log_debug_errno(r, "nl80211: failed to determine genl message command, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
if (IN_SET(cmd, NL80211_CMD_NEW_WIPHY, NL80211_CMD_DEL_WIPHY))
|
||||
return manager_genl_process_nl80211_wiphy(genl, message, manager);
|
||||
if (!IN_SET(cmd, NL80211_CMD_SET_INTERFACE, NL80211_CMD_NEW_INTERFACE, NL80211_CMD_DEL_INTERFACE)) {
|
||||
log_debug("nl80211: ignoring nl80211 %s(%u) message.",
|
||||
strna(nl80211_cmd_to_string(cmd)), cmd);
|
||||
|
||||
205
src/network/networkd-wiphy.c
Normal file
205
src/network/networkd-wiphy.c
Normal file
@@ -0,0 +1,205 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <linux/nl80211.h>
|
||||
|
||||
#include "device-util.h"
|
||||
#include "networkd-manager.h"
|
||||
#include "networkd-wiphy.h"
|
||||
#include "parse-util.h"
|
||||
#include "wifi-util.h"
|
||||
|
||||
Wiphy *wiphy_free(Wiphy *w) {
|
||||
if (!w)
|
||||
return NULL;
|
||||
|
||||
if (w->manager) {
|
||||
hashmap_remove_value(w->manager->wiphy_by_index, UINT32_TO_PTR(w->index), w);
|
||||
if (w->name)
|
||||
hashmap_remove_value(w->manager->wiphy_by_name, w->name, w);
|
||||
}
|
||||
|
||||
free(w->name);
|
||||
return mfree(w);
|
||||
}
|
||||
|
||||
static int wiphy_new(Manager *manager, uint32_t index, Wiphy **ret) {
|
||||
_cleanup_(wiphy_freep) Wiphy *w = NULL;
|
||||
int r;
|
||||
|
||||
assert(manager);
|
||||
|
||||
w = new(Wiphy, 1);
|
||||
if (!w)
|
||||
return -ENOMEM;
|
||||
|
||||
*w = (Wiphy) {
|
||||
.index = index,
|
||||
};
|
||||
|
||||
r = hashmap_ensure_put(&manager->wiphy_by_index, NULL, UINT32_TO_PTR(w->index), w);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
w->manager = manager;
|
||||
|
||||
if (ret)
|
||||
*ret = w;
|
||||
|
||||
TAKE_PTR(w);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wiphy_get_by_index(Manager *manager, uint32_t index, Wiphy **ret) {
|
||||
Wiphy *w;
|
||||
|
||||
assert(manager);
|
||||
|
||||
w = hashmap_get(manager->wiphy_by_index, UINT32_TO_PTR(index));
|
||||
if (!w)
|
||||
return -ENODEV;
|
||||
|
||||
if (ret)
|
||||
*ret = w;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wiphy_get_by_name(Manager *manager, const char *name, Wiphy **ret) {
|
||||
Wiphy *w;
|
||||
|
||||
assert(manager);
|
||||
assert(name);
|
||||
|
||||
w = hashmap_get(manager->wiphy_by_name, name);
|
||||
if (!w)
|
||||
return -ENODEV;
|
||||
|
||||
if (ret)
|
||||
*ret = w;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wiphy_update_name(Wiphy *w, sd_netlink_message *message) {
|
||||
const char *name;
|
||||
int r;
|
||||
|
||||
assert(w);
|
||||
assert(w->manager);
|
||||
assert(message);
|
||||
|
||||
r = sd_netlink_message_read_string(message, NL80211_ATTR_WIPHY_NAME, &name);
|
||||
if (r == -ENODATA)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (streq_ptr(w->name, name))
|
||||
return 0;
|
||||
|
||||
if (w->name)
|
||||
hashmap_remove_value(w->manager->wiphy_by_name, w->name, w);
|
||||
|
||||
r = free_and_strdup(&w->name, name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return hashmap_ensure_put(&w->manager->wiphy_by_name, &string_hash_ops, w->name, w);
|
||||
}
|
||||
|
||||
static int wiphy_update(Wiphy *w, sd_netlink_message *message) {
|
||||
int r;
|
||||
|
||||
assert(w);
|
||||
assert(message);
|
||||
|
||||
r = wiphy_update_name(w, message);
|
||||
if (r < 0)
|
||||
return log_wiphy_debug_errno(w, r, "Failed to update wiphy name: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int manager_genl_process_nl80211_wiphy(sd_netlink *genl, sd_netlink_message *message, Manager *manager) {
|
||||
const char *family;
|
||||
uint32_t index;
|
||||
uint8_t cmd;
|
||||
Wiphy *w = NULL;
|
||||
int r;
|
||||
|
||||
assert(genl);
|
||||
assert(message);
|
||||
assert(manager);
|
||||
|
||||
if (sd_netlink_message_is_error(message)) {
|
||||
r = sd_netlink_message_get_errno(message);
|
||||
if (r < 0)
|
||||
log_message_warning_errno(message, r, "nl80211: received error message, ignoring");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_genl_message_get_family_name(genl, message, &family);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "nl80211: failed to determine genl family, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
if (!streq(family, NL80211_GENL_NAME)) {
|
||||
log_debug("nl80211: Received message of unexpected genl family '%s', ignoring.", family);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_genl_message_get_command(genl, message, &cmd);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "nl80211: failed to determine genl message command, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_netlink_message_read_u32(message, NL80211_ATTR_WIPHY, &index);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "nl80211: received %s(%u) message without valid index, ignoring: %m",
|
||||
strna(nl80211_cmd_to_string(cmd)), cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
(void) wiphy_get_by_index(manager, index, &w);
|
||||
|
||||
switch (cmd) {
|
||||
case NL80211_CMD_NEW_WIPHY: {
|
||||
bool is_new = !w;
|
||||
|
||||
if (!w) {
|
||||
r = wiphy_new(manager, index, &w);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Failed to allocate wiphy, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
r = wiphy_update(w, message);
|
||||
if (r < 0) {
|
||||
log_wiphy_warning_errno(w, r, "Failed to update wiphy, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_wiphy_debug(w, "Received %s phy.", is_new ? "new" : "updated");
|
||||
break;
|
||||
}
|
||||
case NL80211_CMD_DEL_WIPHY:
|
||||
|
||||
if (!w) {
|
||||
log_debug("The kernel removes wiphy we do not know, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_wiphy_debug(w, "Removed.");
|
||||
wiphy_free(w);
|
||||
break;
|
||||
|
||||
default:
|
||||
log_wiphy_debug(w, "nl80211: received %s(%u) message.",
|
||||
strna(nl80211_cmd_to_string(cmd)), cmd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
51
src/network/networkd-wiphy.h
Normal file
51
src/network/networkd-wiphy.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "sd-device.h"
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
typedef struct Manager Manager;
|
||||
|
||||
typedef struct Wiphy {
|
||||
Manager *manager;
|
||||
|
||||
uint32_t index;
|
||||
char *name;
|
||||
} Wiphy;
|
||||
|
||||
Wiphy *wiphy_free(Wiphy *w);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(Wiphy*, wiphy_free);
|
||||
|
||||
int wiphy_get_by_index(Manager *manager, uint32_t index, Wiphy **ret);
|
||||
int wiphy_get_by_name(Manager *manager, const char *name, Wiphy **ret);
|
||||
|
||||
int manager_genl_process_nl80211_wiphy(sd_netlink *genl, sd_netlink_message *message, Manager *manager);
|
||||
|
||||
#define log_wiphy_full_errno_zerook(w, level, error, ...) \
|
||||
({ \
|
||||
const Wiphy *_w = (w); \
|
||||
log_interface_full_errno_zerook(_w ? _w->name : NULL, level, error, __VA_ARGS__); \
|
||||
})
|
||||
|
||||
#define log_wiphy_full_errno(w, level, error, ...) \
|
||||
({ \
|
||||
int _error = (error); \
|
||||
ASSERT_NON_ZERO(_error); \
|
||||
log_wiphy_full_errno_zerook(w, level, _error, __VA_ARGS__); \
|
||||
})
|
||||
|
||||
#define log_wiphy_full(w, level, ...) (void) log_wiphy_full_errno_zerook(w, level, 0, __VA_ARGS__)
|
||||
|
||||
#define log_wiphy_debug(w, ...) log_wiphy_full(w, LOG_DEBUG, __VA_ARGS__)
|
||||
#define log_wiphy_info(w, ...) log_wiphy_full(w, LOG_INFO, __VA_ARGS__)
|
||||
#define log_wiphy_notice(w, ...) log_wiphy_full(w, LOG_NOTICE, __VA_ARGS__)
|
||||
#define log_wiphy_warning(w, ...) log_wiphy_full(w, LOG_WARNING, __VA_ARGS__)
|
||||
#define log_wiphy_error(w, ...) log_wiphy_full(w, LOG_ERR, __VA_ARGS__)
|
||||
|
||||
#define log_wiphy_debug_errno(w, error, ...) log_wiphy_full_errno(w, LOG_DEBUG, error, __VA_ARGS__)
|
||||
#define log_wiphy_info_errno(w, error, ...) log_wiphy_full_errno(w, LOG_INFO, error, __VA_ARGS__)
|
||||
#define log_wiphy_notice_errno(w, error, ...) log_wiphy_full_errno(w, LOG_NOTICE, error, __VA_ARGS__)
|
||||
#define log_wiphy_warning_errno(w, error, ...) log_wiphy_full_errno(w, LOG_WARNING, error, __VA_ARGS__)
|
||||
#define log_wiphy_error_errno(w, error, ...) log_wiphy_full_errno(w, LOG_ERR, error, __VA_ARGS__)
|
||||
@@ -153,7 +153,7 @@ static const char * const nl80211_iftype_table[NUM_NL80211_IFTYPES] = {
|
||||
[NL80211_IFTYPE_NAN] = "nan",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(nl80211_iftype, enum nl80211_iftype);
|
||||
DEFINE_STRING_TABLE_LOOKUP(nl80211_iftype, enum nl80211_iftype);
|
||||
|
||||
static const char * const nl80211_cmd_table[__NL80211_CMD_AFTER_LAST] = {
|
||||
[NL80211_CMD_GET_WIPHY] = "get_wiphy",
|
||||
|
||||
@@ -12,4 +12,5 @@ int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *ret_i
|
||||
int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *ret_bssid);
|
||||
|
||||
const char *nl80211_iftype_to_string(enum nl80211_iftype iftype) _const_;
|
||||
enum nl80211_iftype nl80211_iftype_from_string(const char *s) _pure_;
|
||||
const char *nl80211_cmd_to_string(int cmd) _const_;
|
||||
|
||||
@@ -246,3 +246,7 @@ RoutingAlgorithm=
|
||||
PartitionKey=
|
||||
Mode=
|
||||
IgnoreUserspaceMulticastGroups=
|
||||
[VirtualWLAN]
|
||||
PhysicalDevice=
|
||||
Type=
|
||||
WDS=
|
||||
|
||||
Reference in New Issue
Block a user