hostapd: adjust patches to work with git am
[openwrt/staging/xback.git] / package / network / services / hostapd / patches / 761-shared_das_port.patch
1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Fri, 16 Dec 2022 13:32:48 +0100
3 Subject: [PATCH] hostapd: allow sharing the incoming DAS port across multiple
4 interfaces
5
6 Use the NAS identifier to find the right receiver context on incoming messages
7
8 --- a/src/ap/hostapd.c
9 +++ b/src/ap/hostapd.c
10 @@ -1510,6 +1510,7 @@ int hostapd_setup_bss(struct hostapd_dat
11
12 os_memset(&das_conf, 0, sizeof(das_conf));
13 das_conf.port = conf->radius_das_port;
14 + das_conf.nas_identifier = conf->nas_identifier;
15 das_conf.shared_secret = conf->radius_das_shared_secret;
16 das_conf.shared_secret_len =
17 conf->radius_das_shared_secret_len;
18 --- a/src/radius/radius_das.c
19 +++ b/src/radius/radius_das.c
20 @@ -12,13 +12,26 @@
21 #include "utils/common.h"
22 #include "utils/eloop.h"
23 #include "utils/ip_addr.h"
24 +#include "utils/list.h"
25 #include "radius.h"
26 #include "radius_das.h"
27
28
29 -struct radius_das_data {
30 +static struct dl_list das_ports = DL_LIST_HEAD_INIT(das_ports);
31 +
32 +struct radius_das_port {
33 + struct dl_list list;
34 + struct dl_list das_data;
35 +
36 + int port;
37 int sock;
38 +};
39 +
40 +struct radius_das_data {
41 + struct dl_list list;
42 + struct radius_das_port *port;
43 u8 *shared_secret;
44 + u8 *nas_identifier;
45 size_t shared_secret_len;
46 struct hostapd_ip_addr client_addr;
47 unsigned int time_window;
48 @@ -378,56 +391,17 @@ fail:
49 }
50
51
52 -static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
53 +static void
54 +radius_das_receive_msg(struct radius_das_data *das, struct radius_msg *msg,
55 + struct sockaddr *from, socklen_t fromlen,
56 + char *abuf, int from_port)
57 {
58 - struct radius_das_data *das = eloop_ctx;
59 - u8 buf[1500];
60 - union {
61 - struct sockaddr_storage ss;
62 - struct sockaddr_in sin;
63 -#ifdef CONFIG_IPV6
64 - struct sockaddr_in6 sin6;
65 -#endif /* CONFIG_IPV6 */
66 - } from;
67 - char abuf[50];
68 - int from_port = 0;
69 - socklen_t fromlen;
70 - int len;
71 - struct radius_msg *msg, *reply = NULL;
72 + struct radius_msg *reply = NULL;
73 struct radius_hdr *hdr;
74 struct wpabuf *rbuf;
75 + struct os_time now;
76 u32 val;
77 int res;
78 - struct os_time now;
79 -
80 - fromlen = sizeof(from);
81 - len = recvfrom(sock, buf, sizeof(buf), 0,
82 - (struct sockaddr *) &from.ss, &fromlen);
83 - if (len < 0) {
84 - wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
85 - return;
86 - }
87 -
88 - os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
89 - from_port = ntohs(from.sin.sin_port);
90 -
91 - wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
92 - len, abuf, from_port);
93 - if (das->client_addr.u.v4.s_addr &&
94 - das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
95 - wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
96 - return;
97 - }
98 -
99 - msg = radius_msg_parse(buf, len);
100 - if (msg == NULL) {
101 - wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
102 - "from %s:%d failed", abuf, from_port);
103 - return;
104 - }
105 -
106 - if (wpa_debug_level <= MSG_MSGDUMP)
107 - radius_msg_dump(msg);
108
109 if (radius_msg_verify_das_req(msg, das->shared_secret,
110 das->shared_secret_len,
111 @@ -494,9 +468,8 @@ static void radius_das_receive(int sock,
112 radius_msg_dump(reply);
113
114 rbuf = radius_msg_get_buf(reply);
115 - res = sendto(das->sock, wpabuf_head(rbuf),
116 - wpabuf_len(rbuf), 0,
117 - (struct sockaddr *) &from.ss, fromlen);
118 + res = sendto(das->port->sock, wpabuf_head(rbuf),
119 + wpabuf_len(rbuf), 0, from, fromlen);
120 if (res < 0) {
121 wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s",
122 abuf, from_port, strerror(errno));
123 @@ -508,6 +481,72 @@ fail:
124 radius_msg_free(reply);
125 }
126
127 +static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
128 +{
129 + struct radius_das_port *p = eloop_ctx;
130 + struct radius_das_data *das;
131 + u8 buf[1500];
132 + union {
133 + struct sockaddr_storage ss;
134 + struct sockaddr_in sin;
135 +#ifdef CONFIG_IPV6
136 + struct sockaddr_in6 sin6;
137 +#endif /* CONFIG_IPV6 */
138 + } from;
139 + struct radius_msg *msg;
140 + size_t nasid_len = 0;
141 + u8 *nasid_buf = NULL;
142 + char abuf[50];
143 + int from_port = 0;
144 + socklen_t fromlen;
145 + int found = 0;
146 + int len;
147 +
148 + fromlen = sizeof(from);
149 + len = recvfrom(sock, buf, sizeof(buf), 0,
150 + (struct sockaddr *) &from.ss, &fromlen);
151 + if (len < 0) {
152 + wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
153 + return;
154 + }
155 +
156 + os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
157 + from_port = ntohs(from.sin.sin_port);
158 +
159 + msg = radius_msg_parse(buf, len);
160 + if (msg == NULL) {
161 + wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
162 + "from %s:%d failed", abuf, from_port);
163 + return;
164 + }
165 +
166 + wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
167 + len, abuf, from_port);
168 +
169 + if (wpa_debug_level <= MSG_MSGDUMP)
170 + radius_msg_dump(msg);
171 +
172 + radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
173 + &nasid_buf, &nasid_len, NULL);
174 + dl_list_for_each(das, &p->das_data, struct radius_das_data, list) {
175 + if (das->client_addr.u.v4.s_addr &&
176 + das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr)
177 + continue;
178 +
179 + if (das->nas_identifier && nasid_buf &&
180 + (nasid_len != os_strlen(das->nas_identifier) ||
181 + os_memcmp(das->nas_identifier, nasid_buf, nasid_len) != 0))
182 + continue;
183 +
184 + found = 1;
185 + radius_das_receive_msg(das, msg, (struct sockaddr *)&from.ss,
186 + fromlen, abuf, from_port);
187 + }
188 +
189 + if (!found)
190 + wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
191 +}
192 +
193
194 static int radius_das_open_socket(int port)
195 {
196 @@ -533,6 +572,49 @@ static int radius_das_open_socket(int po
197 }
198
199
200 +static struct radius_das_port *
201 +radius_das_open_port(int port)
202 +{
203 + struct radius_das_port *p;
204 +
205 + dl_list_for_each(p, &das_ports, struct radius_das_port, list) {
206 + if (p->port == port)
207 + return p;
208 + }
209 +
210 + p = os_zalloc(sizeof(*p));
211 + if (p == NULL)
212 + return NULL;
213 +
214 + dl_list_init(&p->das_data);
215 + p->port = port;
216 + p->sock = radius_das_open_socket(port);
217 + if (p->sock < 0)
218 + goto free_port;
219 +
220 + if (eloop_register_read_sock(p->sock, radius_das_receive, p, NULL))
221 + goto close_port;
222 +
223 + dl_list_add(&das_ports, &p->list);
224 +
225 + return p;
226 +
227 +close_port:
228 + close(p->sock);
229 +free_port:
230 + os_free(p);
231 +
232 + return NULL;
233 +}
234 +
235 +static void radius_das_close_port(struct radius_das_port *p)
236 +{
237 + dl_list_del(&p->list);
238 + eloop_unregister_read_sock(p->sock);
239 + close(p->sock);
240 + free(p);
241 +}
242 +
243 struct radius_das_data *
244 radius_das_init(struct radius_das_conf *conf)
245 {
246 @@ -553,6 +635,8 @@ radius_das_init(struct radius_das_conf *
247 das->ctx = conf->ctx;
248 das->disconnect = conf->disconnect;
249 das->coa = conf->coa;
250 + if (conf->nas_identifier)
251 + das->nas_identifier = os_strdup(conf->nas_identifier);
252
253 os_memcpy(&das->client_addr, conf->client_addr,
254 sizeof(das->client_addr));
255 @@ -565,19 +649,15 @@ radius_das_init(struct radius_das_conf *
256 }
257 das->shared_secret_len = conf->shared_secret_len;
258
259 - das->sock = radius_das_open_socket(conf->port);
260 - if (das->sock < 0) {
261 + das->port = radius_das_open_port(conf->port);
262 + if (!das->port) {
263 wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS "
264 "DAS");
265 radius_das_deinit(das);
266 return NULL;
267 }
268
269 - if (eloop_register_read_sock(das->sock, radius_das_receive, das, NULL))
270 - {
271 - radius_das_deinit(das);
272 - return NULL;
273 - }
274 + dl_list_add(&das->port->das_data, &das->list);
275
276 return das;
277 }
278 @@ -588,11 +668,14 @@ void radius_das_deinit(struct radius_das
279 if (das == NULL)
280 return;
281
282 - if (das->sock >= 0) {
283 - eloop_unregister_read_sock(das->sock);
284 - close(das->sock);
285 + if (das->port) {
286 + dl_list_del(&das->list);
287 +
288 + if (dl_list_empty(&das->port->das_data))
289 + radius_das_close_port(das->port);
290 }
291
292 + os_free(das->nas_identifier);
293 os_free(das->shared_secret);
294 os_free(das);
295 }
296 --- a/src/radius/radius_das.h
297 +++ b/src/radius/radius_das.h
298 @@ -44,6 +44,7 @@ struct radius_das_attrs {
299 struct radius_das_conf {
300 int port;
301 const u8 *shared_secret;
302 + const u8 *nas_identifier;
303 size_t shared_secret_len;
304 const struct hostapd_ip_addr *client_addr;
305 unsigned int time_window;