1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <net/if_arp.h>
5 #include "sd-netlink.h"
7 #include "netlink-util.h"
8 #include "networkd-manager.h"
9 #include "networkd-wiphy.h"
10 #include "parse-util.h"
11 #include "wifi-util.h"
14 static void wlan_done(NetDev
*netdev
) {
23 w
->wiphy_name
= mfree(w
->wiphy_name
);
26 static void wlan_init(NetDev
*netdev
) {
35 w
->wiphy_index
= UINT32_MAX
;
39 static int wlan_get_wiphy(NetDev
*netdev
, Wiphy
**ret
) {
49 return wiphy_get_by_name(netdev
->manager
, w
->wiphy_name
, ret
);
51 return wiphy_get_by_index(netdev
->manager
, w
->wiphy_index
, ret
);
54 static int wlan_is_ready_to_create(NetDev
*netdev
, Link
*link
) {
55 return wlan_get_wiphy(netdev
, NULL
) >= 0;
58 static int wlan_fill_message(NetDev
*netdev
, sd_netlink_message
*m
) {
70 r
= wlan_get_wiphy(netdev
, &wiphy
);
74 r
= sd_netlink_message_append_u32(m
, NL80211_ATTR_WIPHY
, wiphy
->index
);
78 r
= sd_netlink_message_append_string(m
, NL80211_ATTR_IFNAME
, netdev
->ifname
);
82 r
= sd_netlink_message_append_u32(m
, NL80211_ATTR_IFTYPE
, w
->iftype
);
86 if (!hw_addr_is_null(&netdev
->hw_addr
) && netdev
->hw_addr
.length
== ETH_ALEN
) {
87 r
= sd_netlink_message_append_ether_addr(m
, NL80211_ATTR_MAC
, &netdev
->hw_addr
.ether
);
93 r
= sd_netlink_message_append_u8(m
, NL80211_ATTR_4ADDR
, w
->wds
);
101 static int wlan_create_handler(sd_netlink
*genl
, sd_netlink_message
*m
, NetDev
*netdev
) {
105 assert(netdev
->state
!= _NETDEV_STATE_INVALID
);
107 r
= sd_netlink_message_get_errno(m
);
108 if (IN_SET(r
, -EEXIST
, -ENFILE
))
109 /* Unlike the other netdevs, the kernel may return -ENFILE. See dev_alloc_name(). */
110 log_netdev_info(netdev
, "WLAN interface exists, using existing without changing its parameters.");
112 log_netdev_warning_errno(netdev
, r
, "WLAN interface could not be created: %m");
113 netdev_enter_failed(netdev
);
118 log_netdev_debug(netdev
, "WLAN interface is created.");
122 static int wlan_create(NetDev
*netdev
) {
123 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
127 assert(netdev
->manager
);
128 assert(netdev
->manager
->genl
);
130 r
= sd_genl_message_new(netdev
->manager
->genl
, NL80211_GENL_NAME
, NL80211_CMD_NEW_INTERFACE
, &m
);
132 return log_netdev_warning_errno(netdev
, r
, "Failed to allocate netlink message: %m");
134 r
= wlan_fill_message(netdev
, m
);
136 return log_netdev_warning_errno(netdev
, r
, "Failed to fill netlink message: %m");
138 r
= netlink_call_async(netdev
->manager
->genl
, NULL
, m
, wlan_create_handler
,
139 netdev_destroy_callback
, netdev
);
141 return log_netdev_warning_errno(netdev
, r
, "Failed to send netlink message: %m");
147 static int wlan_verify(NetDev
*netdev
, const char *filename
) {
157 if (w
->iftype
== NL80211_IFTYPE_UNSPECIFIED
)
158 return log_netdev_warning_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
159 "%s: WLAN interface type is not specified, ignoring.",
162 if (w
->wiphy_index
== UINT32_MAX
&& isempty(w
->wiphy_name
))
163 return log_netdev_warning_errno(netdev
, SYNTHETIC_ERRNO(EINVAL
),
164 "%s: physical WLAN device is not specified, ignoring.",
170 int config_parse_wiphy(
172 const char *filename
,
175 unsigned section_line
,
182 WLan
*w
= ASSERT_PTR(userdata
);
189 if (isempty(rvalue
)) {
190 w
->wiphy_name
= mfree(w
->wiphy_name
);
191 w
->wiphy_index
= UINT32_MAX
;
195 r
= safe_atou32(rvalue
, &w
->wiphy_index
);
197 w
->wiphy_name
= mfree(w
->wiphy_name
);
201 r
= free_and_strdup_warn(&w
->wiphy_name
, rvalue
);
205 w
->wiphy_index
= UINT32_MAX
;
209 int config_parse_wlan_iftype(
211 const char *filename
,
214 unsigned section_line
,
221 enum nl80211_iftype t
, *iftype
= ASSERT_PTR(data
);
227 if (isempty(rvalue
)) {
228 *iftype
= NL80211_IFTYPE_UNSPECIFIED
;
232 t
= nl80211_iftype_from_string(rvalue
);
233 /* We reuse the kernel provided enum which does not contain negative value. So, the cast
234 * below is mandatory. Otherwise, the check below always passes. */
236 log_syntax(unit
, LOG_WARNING
, filename
, line
, t
,
237 "Failed to parse wlan interface type, ignoring assignment: %s",
246 const NetDevVTable wlan_vtable
= {
247 .object_size
= sizeof(WLan
),
250 .sections
= NETDEV_COMMON_SECTIONS
"WLAN\0",
251 .is_ready_to_create
= wlan_is_ready_to_create
,
252 .create
= wlan_create
,
253 .create_type
= NETDEV_CREATE_INDEPENDENT
,
254 .config_verify
= wlan_verify
,
255 .iftype
= ARPHRD_ETHER
,
256 .generate_mac
= true,
257 .skip_netdev_kind_check
= true,