]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/netdev/wlan.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / network / netdev / wlan.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <net/if_arp.h>
4
5 #include "sd-netlink.h"
6
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"
12 #include "wlan.h"
13
14 static void wlan_done(NetDev *netdev) {
15 WLan *w;
16
17 assert(netdev);
18
19 w = WLAN(netdev);
20
21 assert(w);
22
23 w->wiphy_name = mfree(w->wiphy_name);
24 }
25
26 static void wlan_init(NetDev *netdev) {
27 WLan *w;
28
29 assert(netdev);
30
31 w = WLAN(netdev);
32
33 assert(w);
34
35 w->wiphy_index = UINT32_MAX;
36 w->wds = -1;
37 }
38
39 static int wlan_get_wiphy(NetDev *netdev, Wiphy **ret) {
40 WLan *w;
41
42 assert(netdev);
43
44 w = WLAN(netdev);
45
46 assert(w);
47
48 if (w->wiphy_name)
49 return wiphy_get_by_name(netdev->manager, w->wiphy_name, ret);
50
51 return wiphy_get_by_index(netdev->manager, w->wiphy_index, ret);
52 }
53
54 static int wlan_is_ready_to_create(NetDev *netdev, Link *link) {
55 return wlan_get_wiphy(netdev, NULL) >= 0;
56 }
57
58 static int wlan_fill_message(NetDev *netdev, sd_netlink_message *m) {
59 Wiphy *wiphy;
60 WLan *w;
61 int r;
62
63 assert(netdev);
64 assert(m);
65
66 w = WLAN(netdev);
67
68 assert(w);
69
70 r = wlan_get_wiphy(netdev, &wiphy);
71 if (r < 0)
72 return r;
73
74 r = sd_netlink_message_append_u32(m, NL80211_ATTR_WIPHY, wiphy->index);
75 if (r < 0)
76 return r;
77
78 r = sd_netlink_message_append_string(m, NL80211_ATTR_IFNAME, netdev->ifname);
79 if (r < 0)
80 return r;
81
82 r = sd_netlink_message_append_u32(m, NL80211_ATTR_IFTYPE, w->iftype);
83 if (r < 0)
84 return r;
85
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);
88 if (r < 0)
89 return r;
90 }
91
92 if (w->wds >= 0) {
93 r = sd_netlink_message_append_u8(m, NL80211_ATTR_4ADDR, w->wds);
94 if (r < 0)
95 return r;
96 }
97
98 return 0;
99 }
100
101 static int wlan_create_handler(sd_netlink *genl, sd_netlink_message *m, NetDev *netdev) {
102 int r;
103
104 assert(netdev);
105 assert(netdev->state != _NETDEV_STATE_INVALID);
106
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.");
111 else if (r < 0) {
112 log_netdev_warning_errno(netdev, r, "WLAN interface could not be created: %m");
113 netdev_enter_failed(netdev);
114
115 return 1;
116 }
117
118 log_netdev_debug(netdev, "WLAN interface is created.");
119 return 1;
120 }
121
122 static int wlan_create(NetDev *netdev) {
123 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
124 int r;
125
126 assert(netdev);
127 assert(netdev->manager);
128 assert(netdev->manager->genl);
129
130 r = sd_genl_message_new(netdev->manager->genl, NL80211_GENL_NAME, NL80211_CMD_NEW_INTERFACE, &m);
131 if (r < 0)
132 return log_netdev_warning_errno(netdev, r, "Failed to allocate netlink message: %m");
133
134 r = wlan_fill_message(netdev, m);
135 if (r < 0)
136 return log_netdev_warning_errno(netdev, r, "Failed to fill netlink message: %m");
137
138 r = netlink_call_async(netdev->manager->genl, NULL, m, wlan_create_handler,
139 netdev_destroy_callback, netdev);
140 if (r < 0)
141 return log_netdev_warning_errno(netdev, r, "Failed to send netlink message: %m");
142
143 netdev_ref(netdev);
144 return 0;
145 }
146
147 static int wlan_verify(NetDev *netdev, const char *filename) {
148 WLan *w;
149
150 assert(netdev);
151 assert(filename);
152
153 w = WLAN(netdev);
154
155 assert(w);
156
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.",
160 filename);
161
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.",
165 filename);
166
167 return 0;
168 }
169
170 int config_parse_wiphy(
171 const char *unit,
172 const char *filename,
173 unsigned line,
174 const char *section,
175 unsigned section_line,
176 const char *lvalue,
177 int ltype,
178 const char *rvalue,
179 void *data,
180 void *userdata) {
181
182 WLan *w = ASSERT_PTR(userdata);
183 int r;
184
185 assert(filename);
186 assert(lvalue);
187 assert(rvalue);
188
189 if (isempty(rvalue)) {
190 w->wiphy_name = mfree(w->wiphy_name);
191 w->wiphy_index = UINT32_MAX;
192 return 0;
193 }
194
195 r = safe_atou32(rvalue, &w->wiphy_index);
196 if (r >= 0) {
197 w->wiphy_name = mfree(w->wiphy_name);
198 return 0;
199 }
200
201 r = free_and_strdup_warn(&w->wiphy_name, rvalue);
202 if (r < 0)
203 return r;
204
205 w->wiphy_index = UINT32_MAX;
206 return 0;
207 }
208
209 int config_parse_wlan_iftype(
210 const char *unit,
211 const char *filename,
212 unsigned line,
213 const char *section,
214 unsigned section_line,
215 const char *lvalue,
216 int ltype,
217 const char *rvalue,
218 void *data,
219 void *userdata) {
220
221 enum nl80211_iftype t, *iftype = ASSERT_PTR(data);
222
223 assert(filename);
224 assert(lvalue);
225 assert(rvalue);
226
227 if (isempty(rvalue)) {
228 *iftype = NL80211_IFTYPE_UNSPECIFIED;
229 return 0;
230 }
231
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. */
235 if ((int) t < 0) {
236 log_syntax(unit, LOG_WARNING, filename, line, t,
237 "Failed to parse wlan interface type, ignoring assignment: %s",
238 rvalue);
239 return 0;
240 }
241
242 *iftype = t;
243 return 0;
244 }
245
246 const NetDevVTable wlan_vtable = {
247 .object_size = sizeof(WLan),
248 .init = wlan_init,
249 .done = wlan_done,
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,
258 };