Files
systemd/src/network/netdev/wlan.c
T
Zbigniew Jędrzejewski-Szmek 117843fe95 network: make DEFINE_NETDEV_CAST() assert on input and output
The macro used to return NULL if input was NULL or had the wrong type. Now
it asserts that input is nonnull and it has the expected type.

There are a few places where a missing or mismatched type was OK, but in a
majority of places, we would do both of the asserts. In various places we'd
only do one, but that was by ommission/mistake. So moving the asserts into the
macro allows us to save some lines.
2023-09-22 08:17:42 +02:00

229 lines
6.9 KiB
C

/* 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 = WLAN(netdev);
w->wiphy_name = mfree(w->wiphy_name);
}
static void wlan_init(NetDev *netdev) {
WLan *w = WLAN(netdev);
w->wiphy_index = UINT32_MAX;
w->wds = -1;
}
static int wlan_get_wiphy(NetDev *netdev, Wiphy **ret) {
WLan *w = WLAN(netdev);
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) {
WLan *w = WLAN(netdev);
Wiphy *wiphy;
int r;
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 = WLAN(netdev);
assert(filename);
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 = WLAN(userdata);
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
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 = ASSERT_PTR(data);
assert(filename);
assert(lvalue);
assert(rvalue);
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 "WLAN\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,
};