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
wlan_done(NetDev * netdev)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
wlan_init(NetDev * netdev)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
wlan_get_wiphy(NetDev * netdev,Wiphy ** ret)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
wlan_is_ready_to_create(NetDev * netdev,Link * link)54 static int wlan_is_ready_to_create(NetDev *netdev, Link *link) {
55 return wlan_get_wiphy(netdev, NULL) >= 0;
56 }
57
wlan_fill_message(NetDev * netdev,sd_netlink_message * m)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
wlan_create_handler(sd_netlink * genl,sd_netlink_message * m,NetDev * netdev)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
wlan_create(NetDev * netdev)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
wlan_verify(NetDev * netdev,const char * filename)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
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)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 = userdata;
183 int r;
184
185 assert(filename);
186 assert(lvalue);
187 assert(rvalue);
188 assert(userdata);
189
190 if (isempty(rvalue)) {
191 w->wiphy_name = mfree(w->wiphy_name);
192 w->wiphy_index = UINT32_MAX;
193 return 0;
194 }
195
196 r = safe_atou32(rvalue, &w->wiphy_index);
197 if (r >= 0) {
198 w->wiphy_name = mfree(w->wiphy_name);
199 return 0;
200 }
201
202 r = free_and_strdup_warn(&w->wiphy_name, rvalue);
203 if (r < 0)
204 return r;
205
206 w->wiphy_index = UINT32_MAX;
207 return 0;
208 }
209
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)210 int config_parse_wlan_iftype(
211 const char *unit,
212 const char *filename,
213 unsigned line,
214 const char *section,
215 unsigned section_line,
216 const char *lvalue,
217 int ltype,
218 const char *rvalue,
219 void *data,
220 void *userdata) {
221
222 enum nl80211_iftype t, *iftype = data;
223
224 assert(filename);
225 assert(lvalue);
226 assert(rvalue);
227 assert(data);
228
229 if (isempty(rvalue)) {
230 *iftype = NL80211_IFTYPE_UNSPECIFIED;
231 return 0;
232 }
233
234 t = nl80211_iftype_from_string(rvalue);
235 /* We reuse the kernel provided enum which does not contain negative value. So, the cast
236 * below is mandatory. Otherwise, the check below always passes. */
237 if ((int) t < 0) {
238 log_syntax(unit, LOG_WARNING, filename, line, t,
239 "Failed to parse wlan interface type, ignoring assignment: %s",
240 rvalue);
241 return 0;
242 }
243
244 *iftype = t;
245 return 0;
246 }
247
248 const NetDevVTable wlan_vtable = {
249 .object_size = sizeof(WLan),
250 .init = wlan_init,
251 .done = wlan_done,
252 .sections = NETDEV_COMMON_SECTIONS "WLAN\0",
253 .is_ready_to_create = wlan_is_ready_to_create,
254 .create = wlan_create,
255 .create_type = NETDEV_CREATE_INDEPENDENT,
256 .config_verify = wlan_verify,
257 .iftype = ARPHRD_ETHER,
258 .generate_mac = true,
259 .skip_netdev_kind_check = true,
260 };
261