blob: b89a1f431db595f9f82e47981d28348199ab5c04 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * hostapd / VLAN initialization
3 * Copyright 2003, Instant802 Networks, Inc.
4 * Copyright 2005-2006, Devicescape Software, Inc.
5 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
6 *
Dmitry Shmidtfb79edc2014-01-10 10:45:54 -08007 * This software may be distributed under the terms of the BSD license.
8 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07009 */
10
11#include "utils/includes.h"
Dmitry Shmidt1d755d02015-04-28 10:34:29 -070012#ifdef CONFIG_FULL_DYNAMIC_VLAN
13#include <net/if.h>
14#include <sys/ioctl.h>
15#include <linux/sockios.h>
16#include <linux/if_vlan.h>
17#include <linux/if_bridge.h>
18#endif /* CONFIG_FULL_DYNAMIC_VLAN */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070019
20#include "utils/common.h"
21#include "hostapd.h"
22#include "ap_config.h"
23#include "ap_drv_ops.h"
24#include "vlan_init.h"
Dmitry Shmidt61d9df32012-08-29 16:22:06 -070025#include "vlan_util.h"
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070026
27
28#ifdef CONFIG_FULL_DYNAMIC_VLAN
29
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -070030#include "drivers/priv_netlink.h"
31#include "utils/eloop.h"
32
33
34struct full_dynamic_vlan {
35 int s; /* socket on which to listen for new/removed interfaces. */
36};
37
38
39static int ifconfig_helper(const char *if_name, int up)
40{
41 int fd;
42 struct ifreq ifr;
43
44 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
45 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
46 "failed: %s", __func__, strerror(errno));
47 return -1;
48 }
49
50 os_memset(&ifr, 0, sizeof(ifr));
51 os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
52
53 if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
54 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
55 "for interface %s: %s",
56 __func__, if_name, strerror(errno));
57 close(fd);
58 return -1;
59 }
60
61 if (up)
62 ifr.ifr_flags |= IFF_UP;
63 else
64 ifr.ifr_flags &= ~IFF_UP;
65
66 if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
67 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
68 "for interface %s (up=%d): %s",
69 __func__, if_name, up, strerror(errno));
70 close(fd);
71 return -1;
72 }
73
74 close(fd);
75 return 0;
76}
77
78
79static int ifconfig_up(const char *if_name)
80{
81 wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
82 return ifconfig_helper(if_name, 1);
83}
84
85
86static int ifconfig_down(const char *if_name)
87{
88 wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
89 return ifconfig_helper(if_name, 0);
90}
91
92
93/*
94 * These are only available in recent linux headers (without the leading
95 * underscore).
96 */
97#define _GET_VLAN_REALDEV_NAME_CMD 8
98#define _GET_VLAN_VID_CMD 9
99
100/* This value should be 256 ONLY. If it is something else, then hostapd
101 * might crash!, as this value has been hard-coded in 2.4.x kernel
102 * bridging code.
103 */
104#define MAX_BR_PORTS 256
105
106static int br_delif(const char *br_name, const char *if_name)
107{
108 int fd;
109 struct ifreq ifr;
110 unsigned long args[2];
111 int if_index;
112
113 wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
114 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
115 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
116 "failed: %s", __func__, strerror(errno));
117 return -1;
118 }
119
120 if_index = if_nametoindex(if_name);
121
122 if (if_index == 0) {
123 wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
124 "interface index for '%s'",
125 __func__, if_name);
126 close(fd);
127 return -1;
128 }
129
130 args[0] = BRCTL_DEL_IF;
131 args[1] = if_index;
132
133 os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
134 ifr.ifr_data = (__caddr_t) args;
135
136 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
137 /* No error if interface already removed. */
138 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
139 "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
140 "%s", __func__, br_name, if_name, strerror(errno));
141 close(fd);
142 return -1;
143 }
144
145 close(fd);
146 return 0;
147}
148
149
150/*
151 Add interface 'if_name' to the bridge 'br_name'
152
153 returns -1 on error
154 returns 1 if the interface is already part of the bridge
155 returns 0 otherwise
156*/
157static int br_addif(const char *br_name, const char *if_name)
158{
159 int fd;
160 struct ifreq ifr;
161 unsigned long args[2];
162 int if_index;
163
164 wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
165 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
166 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
167 "failed: %s", __func__, strerror(errno));
168 return -1;
169 }
170
171 if_index = if_nametoindex(if_name);
172
173 if (if_index == 0) {
174 wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
175 "interface index for '%s'",
176 __func__, if_name);
177 close(fd);
178 return -1;
179 }
180
181 args[0] = BRCTL_ADD_IF;
182 args[1] = if_index;
183
184 os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
185 ifr.ifr_data = (__caddr_t) args;
186
187 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
188 if (errno == EBUSY) {
189 /* The interface is already added. */
190 close(fd);
191 return 1;
192 }
193
194 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
195 "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
196 "%s", __func__, br_name, if_name, strerror(errno));
197 close(fd);
198 return -1;
199 }
200
201 close(fd);
202 return 0;
203}
204
205
206static int br_delbr(const char *br_name)
207{
208 int fd;
209 unsigned long arg[2];
210
211 wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
212 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
213 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
214 "failed: %s", __func__, strerror(errno));
215 return -1;
216 }
217
218 arg[0] = BRCTL_DEL_BRIDGE;
219 arg[1] = (unsigned long) br_name;
220
221 if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
222 /* No error if bridge already removed. */
223 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
224 "%s: %s", __func__, br_name, strerror(errno));
225 close(fd);
226 return -1;
227 }
228
229 close(fd);
230 return 0;
231}
232
233
234/*
235 Add a bridge with the name 'br_name'.
236
237 returns -1 on error
238 returns 1 if the bridge already exists
239 returns 0 otherwise
240*/
241static int br_addbr(const char *br_name)
242{
243 int fd;
244 unsigned long arg[4];
245 struct ifreq ifr;
246
247 wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
248 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
249 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
250 "failed: %s", __func__, strerror(errno));
251 return -1;
252 }
253
254 arg[0] = BRCTL_ADD_BRIDGE;
255 arg[1] = (unsigned long) br_name;
256
257 if (ioctl(fd, SIOCGIFBR, arg) < 0) {
258 if (errno == EEXIST) {
259 /* The bridge is already added. */
260 close(fd);
261 return 1;
262 } else {
263 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
264 "failed for %s: %s",
265 __func__, br_name, strerror(errno));
266 close(fd);
267 return -1;
268 }
269 }
270
271 /* Decrease forwarding delay to avoid EAPOL timeouts. */
272 os_memset(&ifr, 0, sizeof(ifr));
273 os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
274 arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
275 arg[1] = 1;
276 arg[2] = 0;
277 arg[3] = 0;
278 ifr.ifr_data = (char *) &arg;
279 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
280 wpa_printf(MSG_ERROR, "VLAN: %s: "
281 "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
282 "%s: %s", __func__, br_name, strerror(errno));
283 /* Continue anyway */
284 }
285
286 close(fd);
287 return 0;
288}
289
290
291static int br_getnumports(const char *br_name)
292{
293 int fd;
294 int i;
295 int port_cnt = 0;
296 unsigned long arg[4];
297 int ifindices[MAX_BR_PORTS];
298 struct ifreq ifr;
299
300 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
301 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
302 "failed: %s", __func__, strerror(errno));
303 return -1;
304 }
305
306 arg[0] = BRCTL_GET_PORT_LIST;
307 arg[1] = (unsigned long) ifindices;
308 arg[2] = MAX_BR_PORTS;
309 arg[3] = 0;
310
311 os_memset(ifindices, 0, sizeof(ifindices));
312 os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
313 ifr.ifr_data = (__caddr_t) arg;
314
315 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
316 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
317 "failed for %s: %s",
318 __func__, br_name, strerror(errno));
319 close(fd);
320 return -1;
321 }
322
323 for (i = 1; i < MAX_BR_PORTS; i++) {
324 if (ifindices[i] > 0) {
325 port_cnt++;
326 }
327 }
328
329 close(fd);
330 return port_cnt;
331}
332
333
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700334#ifndef CONFIG_VLAN_NETLINK
335
336int vlan_rem(const char *if_name)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700337{
338 int fd;
339 struct vlan_ioctl_args if_request;
340
341 wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
342 if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
343 wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
344 if_name);
345 return -1;
346 }
347
348 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
349 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
350 "failed: %s", __func__, strerror(errno));
351 return -1;
352 }
353
354 os_memset(&if_request, 0, sizeof(if_request));
355
356 os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
357 if_request.cmd = DEL_VLAN_CMD;
358
359 if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
360 wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
361 "%s", __func__, if_name, strerror(errno));
362 close(fd);
363 return -1;
364 }
365
366 close(fd);
367 return 0;
368}
369
370
371/*
372 Add a vlan interface with VLAN ID 'vid' and tagged interface
373 'if_name'.
374
375 returns -1 on error
376 returns 1 if the interface already exists
377 returns 0 otherwise
378*/
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700379int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700380{
381 int fd;
382 struct vlan_ioctl_args if_request;
383
384 wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
385 if_name, vid);
386 ifconfig_up(if_name);
387
388 if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
389 wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
390 if_name);
391 return -1;
392 }
393
394 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
395 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
396 "failed: %s", __func__, strerror(errno));
397 return -1;
398 }
399
400 os_memset(&if_request, 0, sizeof(if_request));
401
402 /* Determine if a suitable vlan device already exists. */
403
404 os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
405 vid);
406
407 if_request.cmd = _GET_VLAN_VID_CMD;
408
409 if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
410
411 if (if_request.u.VID == vid) {
412 if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
413
414 if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
415 os_strncmp(if_request.u.device2, if_name,
416 sizeof(if_request.u.device2)) == 0) {
417 close(fd);
418 wpa_printf(MSG_DEBUG, "VLAN: vlan_add: "
419 "if_name %s exists already",
420 if_request.device1);
421 return 1;
422 }
423 }
424 }
425
426 /* A suitable vlan device does not already exist, add one. */
427
428 os_memset(&if_request, 0, sizeof(if_request));
429 os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
430 if_request.u.VID = vid;
431 if_request.cmd = ADD_VLAN_CMD;
432
433 if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
434 wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: "
435 "%s",
436 __func__, if_request.device1, strerror(errno));
437 close(fd);
438 return -1;
439 }
440
441 close(fd);
442 return 0;
443}
444
445
446static int vlan_set_name_type(unsigned int name_type)
447{
448 int fd;
449 struct vlan_ioctl_args if_request;
450
451 wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
452 name_type);
453 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
454 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
455 "failed: %s", __func__, strerror(errno));
456 return -1;
457 }
458
459 os_memset(&if_request, 0, sizeof(if_request));
460
461 if_request.u.name_type = name_type;
462 if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
463 if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
464 wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD "
465 "name_type=%u failed: %s",
466 __func__, name_type, strerror(errno));
467 close(fd);
468 return -1;
469 }
470
471 close(fd);
472 return 0;
473}
474
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700475#endif /* CONFIG_VLAN_NETLINK */
476
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700477
478static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
479{
480 char vlan_ifname[IFNAMSIZ];
481 char br_name[IFNAMSIZ];
482 struct hostapd_vlan *vlan = hapd->conf->vlan;
483 char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700484 int vlan_naming = hapd->conf->ssid.vlan_naming;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700485
486 wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
487
488 while (vlan) {
Dmitry Shmidt83474442015-04-15 13:47:09 -0700489 if (os_strcmp(ifname, vlan->ifname) == 0 && !vlan->configured) {
490 vlan->configured = 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700491
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700492 if (hapd->conf->vlan_bridge[0]) {
493 os_snprintf(br_name, sizeof(br_name), "%s%d",
494 hapd->conf->vlan_bridge,
495 vlan->vlan_id);
496 } else if (tagged_interface) {
497 os_snprintf(br_name, sizeof(br_name),
498 "br%s.%d", tagged_interface,
499 vlan->vlan_id);
500 } else {
501 os_snprintf(br_name, sizeof(br_name),
502 "brvlan%d", vlan->vlan_id);
503 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700504
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700505 if (!br_addbr(br_name))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700506 vlan->clean |= DVLAN_CLEAN_BR;
507
508 ifconfig_up(br_name);
509
510 if (tagged_interface) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700511 if (vlan_naming ==
512 DYNAMIC_VLAN_NAMING_WITH_DEVICE)
513 os_snprintf(vlan_ifname,
514 sizeof(vlan_ifname),
515 "%s.%d", tagged_interface,
516 vlan->vlan_id);
517 else
518 os_snprintf(vlan_ifname,
519 sizeof(vlan_ifname),
520 "vlan%d", vlan->vlan_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700521
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700522 ifconfig_up(tagged_interface);
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700523 if (!vlan_add(tagged_interface, vlan->vlan_id,
524 vlan_ifname))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700525 vlan->clean |= DVLAN_CLEAN_VLAN;
526
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700527 if (!br_addif(br_name, vlan_ifname))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700528 vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
529
530 ifconfig_up(vlan_ifname);
531 }
532
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700533 if (!br_addif(br_name, ifname))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700534 vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
535
536 ifconfig_up(ifname);
537
538 break;
539 }
540 vlan = vlan->next;
541 }
542}
543
544
545static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
546{
547 char vlan_ifname[IFNAMSIZ];
548 char br_name[IFNAMSIZ];
549 struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
550 char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700551 int vlan_naming = hapd->conf->ssid.vlan_naming;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700552
553 wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
554
555 first = prev = vlan;
556
557 while (vlan) {
558 if (os_strcmp(ifname, vlan->ifname) == 0) {
Dmitry Shmidt34af3062013-07-11 10:46:32 -0700559 if (hapd->conf->vlan_bridge[0]) {
560 os_snprintf(br_name, sizeof(br_name), "%s%d",
561 hapd->conf->vlan_bridge,
562 vlan->vlan_id);
563 } else if (tagged_interface) {
564 os_snprintf(br_name, sizeof(br_name),
565 "br%s.%d", tagged_interface,
566 vlan->vlan_id);
567 } else {
568 os_snprintf(br_name, sizeof(br_name),
569 "brvlan%d", vlan->vlan_id);
570 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700571
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700572 if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700573 br_delif(br_name, vlan->ifname);
574
575 if (tagged_interface) {
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700576 if (vlan_naming ==
577 DYNAMIC_VLAN_NAMING_WITH_DEVICE)
578 os_snprintf(vlan_ifname,
579 sizeof(vlan_ifname),
580 "%s.%d", tagged_interface,
581 vlan->vlan_id);
582 else
583 os_snprintf(vlan_ifname,
584 sizeof(vlan_ifname),
585 "vlan%d", vlan->vlan_id);
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700586 if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700587 br_delif(br_name, vlan_ifname);
588 ifconfig_down(vlan_ifname);
589
Dmitry Shmidt818ea482014-03-10 13:15:21 -0700590 if (vlan->clean & DVLAN_CLEAN_VLAN)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700591 vlan_rem(vlan_ifname);
592 }
593
594 if ((vlan->clean & DVLAN_CLEAN_BR) &&
595 br_getnumports(br_name) == 0) {
596 ifconfig_down(br_name);
597 br_delbr(br_name);
598 }
599
600 if (vlan == first) {
601 hapd->conf->vlan = vlan->next;
602 } else {
603 prev->next = vlan->next;
604 }
605 os_free(vlan);
606
607 break;
608 }
609 prev = vlan;
610 vlan = vlan->next;
611 }
612}
613
614
615static void
616vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
617 struct hostapd_data *hapd)
618{
619 struct ifinfomsg *ifi;
620 int attrlen, nlmsg_len, rta_len;
621 struct rtattr *attr;
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800622 char ifname[IFNAMSIZ + 1];
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700623
624 if (len < sizeof(*ifi))
625 return;
626
627 ifi = NLMSG_DATA(h);
628
629 nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
630
631 attrlen = h->nlmsg_len - nlmsg_len;
632 if (attrlen < 0)
633 return;
634
635 attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
636
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800637 os_memset(ifname, 0, sizeof(ifname));
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700638 rta_len = RTA_ALIGN(sizeof(struct rtattr));
639 while (RTA_OK(attr, attrlen)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700640 if (attr->rta_type == IFLA_IFNAME) {
641 int n = attr->rta_len - rta_len;
642 if (n < 0)
643 break;
644
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800645 if ((size_t) n >= sizeof(ifname))
646 n = sizeof(ifname) - 1;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700647 os_memcpy(ifname, ((char *) attr) + rta_len, n);
648
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700649 }
650
651 attr = RTA_NEXT(attr, attrlen);
652 }
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800653
654 if (!ifname[0])
655 return;
Dmitry Shmidt83474442015-04-15 13:47:09 -0700656 if (del && if_nametoindex(ifname)) {
657 /* interface still exists, race condition ->
658 * iface has just been recreated */
659 return;
660 }
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800661
662 wpa_printf(MSG_DEBUG,
663 "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
664 del ? "DEL" : "NEW",
665 ifi->ifi_index, ifname, ifi->ifi_family, ifi->ifi_flags,
666 (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
667 (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
668 (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
669 (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
670
671 if (del)
672 vlan_dellink(ifname, hapd);
673 else
674 vlan_newlink(ifname, hapd);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700675}
676
677
678static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
679{
680 char buf[8192];
681 int left;
682 struct sockaddr_nl from;
683 socklen_t fromlen;
684 struct nlmsghdr *h;
685 struct hostapd_data *hapd = eloop_ctx;
686
687 fromlen = sizeof(from);
688 left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
689 (struct sockaddr *) &from, &fromlen);
690 if (left < 0) {
691 if (errno != EINTR && errno != EAGAIN)
692 wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
693 __func__, strerror(errno));
694 return;
695 }
696
697 h = (struct nlmsghdr *) buf;
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800698 while (NLMSG_OK(h, left)) {
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700699 int len, plen;
700
701 len = h->nlmsg_len;
702 plen = len - sizeof(*h);
703 if (len > left || plen < 0) {
704 wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
705 "message: len=%d left=%d plen=%d",
706 len, left, plen);
707 break;
708 }
709
710 switch (h->nlmsg_type) {
711 case RTM_NEWLINK:
712 vlan_read_ifnames(h, plen, 0, hapd);
713 break;
714 case RTM_DELLINK:
715 vlan_read_ifnames(h, plen, 1, hapd);
716 break;
717 }
718
Dmitry Shmidt7f656022015-02-25 14:36:37 -0800719 h = NLMSG_NEXT(h, left);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700720 }
721
722 if (left > 0) {
723 wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
724 "netlink message", __func__, left);
725 }
726}
727
728
729static struct full_dynamic_vlan *
730full_dynamic_vlan_init(struct hostapd_data *hapd)
731{
732 struct sockaddr_nl local;
733 struct full_dynamic_vlan *priv;
734
735 priv = os_zalloc(sizeof(*priv));
736 if (priv == NULL)
737 return NULL;
738
Dmitry Shmidt61d9df32012-08-29 16:22:06 -0700739#ifndef CONFIG_VLAN_NETLINK
740 vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
741 DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
742 VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
743 VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
744#endif /* CONFIG_VLAN_NETLINK */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700745
746 priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
747 if (priv->s < 0) {
748 wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
749 "NETLINK_ROUTE) failed: %s",
750 __func__, strerror(errno));
751 os_free(priv);
752 return NULL;
753 }
754
755 os_memset(&local, 0, sizeof(local));
756 local.nl_family = AF_NETLINK;
757 local.nl_groups = RTMGRP_LINK;
758 if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
759 wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
760 __func__, strerror(errno));
761 close(priv->s);
762 os_free(priv);
763 return NULL;
764 }
765
766 if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
767 {
768 close(priv->s);
769 os_free(priv);
770 return NULL;
771 }
772
773 return priv;
774}
775
776
777static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
778{
779 if (priv == NULL)
780 return;
781 eloop_unregister_read_sock(priv->s);
782 close(priv->s);
783 os_free(priv);
784}
785#endif /* CONFIG_FULL_DYNAMIC_VLAN */
786
787
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700788int vlan_setup_encryption_dyn(struct hostapd_data *hapd, const char *dyn_vlan)
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700789{
790 int i;
791
792 if (dyn_vlan == NULL)
793 return 0;
794
795 /* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
796 * functions for setting up dynamic broadcast keys. */
797 for (i = 0; i < 4; i++) {
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700798 if (hapd->conf->ssid.wep.key[i] &&
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700799 hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
Dmitry Shmidt9d9e6022015-04-23 10:34:55 -0700800 i == hapd->conf->ssid.wep.idx, NULL, 0,
801 hapd->conf->ssid.wep.key[i],
802 hapd->conf->ssid.wep.len[i]))
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700803 {
804 wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
805 "encryption for dynamic VLAN");
806 return -1;
807 }
808 }
809
810 return 0;
811}
812
813
814static int vlan_dynamic_add(struct hostapd_data *hapd,
815 struct hostapd_vlan *vlan)
816{
817 while (vlan) {
818 if (vlan->vlan_id != VLAN_ID_WILDCARD) {
819 if (hostapd_vlan_if_add(hapd, vlan->ifname)) {
820 if (errno != EEXIST) {
821 wpa_printf(MSG_ERROR, "VLAN: Could "
822 "not add VLAN %s: %s",
823 vlan->ifname,
824 strerror(errno));
825 return -1;
826 }
827 }
828#ifdef CONFIG_FULL_DYNAMIC_VLAN
829 ifconfig_up(vlan->ifname);
830#endif /* CONFIG_FULL_DYNAMIC_VLAN */
831 }
832
833 vlan = vlan->next;
834 }
835
836 return 0;
837}
838
839
840static void vlan_dynamic_remove(struct hostapd_data *hapd,
841 struct hostapd_vlan *vlan)
842{
843 struct hostapd_vlan *next;
844
845 while (vlan) {
846 next = vlan->next;
847
848 if (vlan->vlan_id != VLAN_ID_WILDCARD &&
849 hostapd_vlan_if_remove(hapd, vlan->ifname)) {
850 wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
851 "iface: %s: %s",
852 vlan->ifname, strerror(errno));
853 }
854#ifdef CONFIG_FULL_DYNAMIC_VLAN
855 if (vlan->clean)
856 vlan_dellink(vlan->ifname, hapd);
857#endif /* CONFIG_FULL_DYNAMIC_VLAN */
858
859 vlan = next;
860 }
861}
862
863
864int vlan_init(struct hostapd_data *hapd)
865{
866#ifdef CONFIG_FULL_DYNAMIC_VLAN
867 hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
868#endif /* CONFIG_FULL_DYNAMIC_VLAN */
869
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700870 if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
871 !hapd->conf->vlan) {
872 /* dynamic vlans enabled but no (or empty) vlan_file given */
873 struct hostapd_vlan *vlan;
874 vlan = os_zalloc(sizeof(*vlan));
875 if (vlan == NULL) {
876 wpa_printf(MSG_ERROR, "Out of memory while assigning "
877 "VLAN interfaces");
878 return -1;
879 }
880
881 vlan->vlan_id = VLAN_ID_WILDCARD;
882 os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
883 hapd->conf->iface);
Dmitry Shmidtd5c075b2013-08-05 14:36:10 -0700884 vlan->next = hapd->conf->vlan;
885 hapd->conf->vlan = vlan;
Dmitry Shmidt4b060592013-04-29 16:42:49 -0700886 }
887
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700888 if (vlan_dynamic_add(hapd, hapd->conf->vlan))
889 return -1;
890
891 return 0;
892}
893
894
895void vlan_deinit(struct hostapd_data *hapd)
896{
897 vlan_dynamic_remove(hapd, hapd->conf->vlan);
898
899#ifdef CONFIG_FULL_DYNAMIC_VLAN
900 full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
Dmitry Shmidt56052862013-10-04 10:23:25 -0700901 hapd->full_dynamic_vlan = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700902#endif /* CONFIG_FULL_DYNAMIC_VLAN */
903}
904
905
906struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
907 struct hostapd_vlan *vlan,
908 int vlan_id)
909{
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800910 struct hostapd_vlan *n = NULL;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700911 char *ifname, *pos;
912
913 if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
914 vlan->vlan_id != VLAN_ID_WILDCARD)
915 return NULL;
916
917 wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
918 __func__, vlan_id, vlan->ifname);
919 ifname = os_strdup(vlan->ifname);
920 if (ifname == NULL)
921 return NULL;
922 pos = os_strchr(ifname, '#');
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800923 if (pos == NULL)
924 goto free_ifname;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700925 *pos++ = '\0';
926
927 n = os_zalloc(sizeof(*n));
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800928 if (n == NULL)
929 goto free_ifname;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700930
931 n->vlan_id = vlan_id;
932 n->dynamic_vlan = 1;
933
934 os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
935 pos);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700936
937 if (hostapd_vlan_if_add(hapd, n->ifname)) {
938 os_free(n);
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800939 n = NULL;
940 goto free_ifname;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700941 }
942
943 n->next = hapd->conf->vlan;
944 hapd->conf->vlan = n;
945
946#ifdef CONFIG_FULL_DYNAMIC_VLAN
947 ifconfig_up(n->ifname);
948#endif /* CONFIG_FULL_DYNAMIC_VLAN */
949
Dmitry Shmidt216983b2015-02-06 10:50:36 -0800950free_ifname:
951 os_free(ifname);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700952 return n;
953}
954
955
956int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
957{
958 struct hostapd_vlan *vlan;
959
960 if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
961 return 1;
962
Dmitry Shmidt83474442015-04-15 13:47:09 -0700963 wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
964 __func__, hapd->conf->iface, vlan_id);
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700965
966 vlan = hapd->conf->vlan;
967 while (vlan) {
968 if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
969 vlan->dynamic_vlan--;
970 break;
971 }
972 vlan = vlan->next;
973 }
974
975 if (vlan == NULL)
976 return 1;
977
978 if (vlan->dynamic_vlan == 0)
979 hostapd_vlan_if_remove(hapd, vlan->ifname);
980
981 return 0;
982}