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