00001
00017 #include "includes.h"
00018
00019 #include "hostapd.h"
00020 #include "driver_i.h"
00021 #include "vlan_init.h"
00022
00023
00024 #ifdef CONFIG_FULL_DYNAMIC_VLAN
00025
00026 #include <net/if.h>
00027 #include <sys/ioctl.h>
00028 #include <linux/sockios.h>
00029 #include <linux/if_vlan.h>
00030 #include <linux/if_bridge.h>
00031
00032 #include "drivers/priv_netlink.h"
00033 #include "eloop.h"
00034
00035
00036 struct full_dynamic_vlan {
00037 int s;
00038 };
00039
00040
00041 static int ifconfig_helper(const char *if_name, int up)
00042 {
00043 int fd;
00044 struct ifreq ifr;
00045
00046 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
00047 perror("socket[AF_INET,SOCK_STREAM]");
00048 return -1;
00049 }
00050
00051 os_memset(&ifr, 0, sizeof(ifr));
00052 os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
00053
00054 if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
00055 perror("ioctl[SIOCGIFFLAGS]");
00056 close(fd);
00057 return -1;
00058 }
00059
00060 if (up)
00061 ifr.ifr_flags |= IFF_UP;
00062 else
00063 ifr.ifr_flags &= ~IFF_UP;
00064
00065 if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
00066 perror("ioctl[SIOCSIFFLAGS]");
00067 close(fd);
00068 return -1;
00069 }
00070
00071 close(fd);
00072 return 0;
00073 }
00074
00075
00076 static int ifconfig_up(const char *if_name)
00077 {
00078 return ifconfig_helper(if_name, 1);
00079 }
00080
00081
00082 static int ifconfig_down(const char *if_name)
00083 {
00084 return ifconfig_helper(if_name, 0);
00085 }
00086
00087
00088
00089
00090
00091
00092 #define _GET_VLAN_REALDEV_NAME_CMD 8
00093 #define _GET_VLAN_VID_CMD 9
00094
00095
00096
00097
00098
00099 #define MAX_BR_PORTS 256
00100
00101 static int br_delif(const char *br_name, const char *if_name)
00102 {
00103 int fd;
00104 struct ifreq ifr;
00105 unsigned long args[2];
00106 int if_index;
00107
00108 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
00109 perror("socket[AF_INET,SOCK_STREAM]");
00110 return -1;
00111 }
00112
00113 if_index = if_nametoindex(if_name);
00114
00115 if (if_index == 0) {
00116 printf("Failure determining interface index for '%s'\n",
00117 if_name);
00118 close(fd);
00119 return -1;
00120 }
00121
00122 args[0] = BRCTL_DEL_IF;
00123 args[1] = if_index;
00124
00125 os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
00126 ifr.ifr_data = (__caddr_t) args;
00127
00128 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
00129
00130 perror("ioctl[SIOCDEVPRIVATE,BRCTL_DEL_IF]");
00131 close(fd);
00132 return -1;
00133 }
00134
00135 close(fd);
00136 return 0;
00137 }
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147 static int br_addif(const char *br_name, const char *if_name)
00148 {
00149 int fd;
00150 struct ifreq ifr;
00151 unsigned long args[2];
00152 int if_index;
00153
00154 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
00155 perror("socket[AF_INET,SOCK_STREAM]");
00156 return -1;
00157 }
00158
00159 if_index = if_nametoindex(if_name);
00160
00161 if (if_index == 0) {
00162 printf("Failure determining interface index for '%s'\n",
00163 if_name);
00164 close(fd);
00165 return -1;
00166 }
00167
00168 args[0] = BRCTL_ADD_IF;
00169 args[1] = if_index;
00170
00171 os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
00172 ifr.ifr_data = (__caddr_t) args;
00173
00174 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
00175 if (errno == EBUSY) {
00176
00177 close(fd);
00178 return 1;
00179 }
00180
00181 perror("ioctl[SIOCDEVPRIVATE,BRCTL_ADD_IF]");
00182 close(fd);
00183 return -1;
00184 }
00185
00186 close(fd);
00187 return 0;
00188 }
00189
00190
00191 static int br_delbr(const char *br_name)
00192 {
00193 int fd;
00194 unsigned long arg[2];
00195
00196 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
00197 perror("socket[AF_INET,SOCK_STREAM]");
00198 return -1;
00199 }
00200
00201 arg[0] = BRCTL_DEL_BRIDGE;
00202 arg[1] = (unsigned long) br_name;
00203
00204 if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
00205
00206 perror("ioctl[BRCTL_DEL_BRIDGE]");
00207 close(fd);
00208 return -1;
00209 }
00210
00211 close(fd);
00212 return 0;
00213 }
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223 static int br_addbr(const char *br_name)
00224 {
00225 int fd;
00226 unsigned long arg[2];
00227
00228 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
00229 perror("socket[AF_INET,SOCK_STREAM]");
00230 return -1;
00231 }
00232
00233 arg[0] = BRCTL_ADD_BRIDGE;
00234 arg[1] = (unsigned long) br_name;
00235
00236 if (ioctl(fd, SIOCGIFBR, arg) < 0) {
00237 if (errno == EEXIST) {
00238
00239 close(fd);
00240 return 1;
00241 } else {
00242 perror("ioctl[BRCTL_ADD_BRIDGE]");
00243 close(fd);
00244 return -1;
00245 }
00246 }
00247
00248 close(fd);
00249 return 0;
00250 }
00251
00252
00253 static int br_getnumports(const char *br_name)
00254 {
00255 int fd;
00256 int i;
00257 int port_cnt = 0;
00258 unsigned long arg[4];
00259 int ifindices[MAX_BR_PORTS];
00260 struct ifreq ifr;
00261
00262 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
00263 perror("socket[AF_INET,SOCK_STREAM]");
00264 return -1;
00265 }
00266
00267 arg[0] = BRCTL_GET_PORT_LIST;
00268 arg[1] = (unsigned long) ifindices;
00269 arg[2] = MAX_BR_PORTS;
00270 arg[3] = 0;
00271
00272 os_memset(ifindices, 0, sizeof(ifindices));
00273 os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
00274 ifr.ifr_data = (__caddr_t) arg;
00275
00276 if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
00277 perror("ioctl[SIOCDEVPRIVATE,BRCTL_GET_PORT_LIST]");
00278 close(fd);
00279 return -1;
00280 }
00281
00282 for (i = 1; i < MAX_BR_PORTS; i++) {
00283 if (ifindices[i] > 0) {
00284 port_cnt++;
00285 }
00286 }
00287
00288 close(fd);
00289 return port_cnt;
00290 }
00291
00292
00293 static int vlan_rem(const char *if_name)
00294 {
00295 int fd;
00296 struct vlan_ioctl_args if_request;
00297
00298 if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
00299 fprintf(stderr, "Interface name to long.\n");
00300 return -1;
00301 }
00302
00303 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
00304 perror("socket[AF_INET,SOCK_STREAM]");
00305 return -1;
00306 }
00307
00308 os_memset(&if_request, 0, sizeof(if_request));
00309
00310 os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
00311 if_request.cmd = DEL_VLAN_CMD;
00312
00313 if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
00314 perror("ioctl[SIOCSIFVLAN,DEL_VLAN_CMD]");
00315 close(fd);
00316 return -1;
00317 }
00318
00319 close(fd);
00320 return 0;
00321 }
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332 static int vlan_add(const char *if_name, int vid)
00333 {
00334 int fd;
00335 struct vlan_ioctl_args if_request;
00336
00337 ifconfig_up(if_name);
00338
00339 if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
00340 fprintf(stderr, "Interface name to long.\n");
00341 return -1;
00342 }
00343
00344 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
00345 perror("socket[AF_INET,SOCK_STREAM]");
00346 return -1;
00347 }
00348
00349 os_memset(&if_request, 0, sizeof(if_request));
00350
00351
00352
00353 os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
00354 vid);
00355
00356 if_request.cmd = _GET_VLAN_VID_CMD;
00357
00358 if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
00359
00360 if (if_request.u.VID == vid) {
00361 if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
00362
00363 if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
00364 os_strncmp(if_request.u.device2, if_name,
00365 sizeof(if_request.u.device2)) == 0) {
00366 close(fd);
00367 return 1;
00368 }
00369 }
00370 }
00371
00372
00373
00374 os_memset(&if_request, 0, sizeof(if_request));
00375 os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
00376 if_request.u.VID = vid;
00377 if_request.cmd = ADD_VLAN_CMD;
00378
00379 if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
00380 perror("ioctl[SIOCSIFVLAN,ADD_VLAN_CMD]");
00381 close(fd);
00382 return -1;
00383 }
00384
00385 close(fd);
00386 return 0;
00387 }
00388
00389
00390 static int vlan_set_name_type(unsigned int name_type)
00391 {
00392 int fd;
00393 struct vlan_ioctl_args if_request;
00394
00395 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
00396 perror("socket[AF_INET,SOCK_STREAM]");
00397 return -1;
00398 }
00399
00400 os_memset(&if_request, 0, sizeof(if_request));
00401
00402 if_request.u.name_type = name_type;
00403 if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
00404 if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
00405 perror("ioctl[SIOCSIFVLAN,SET_VLAN_NAME_TYPE_CMD]");
00406 close(fd);
00407 return -1;
00408 }
00409
00410 close(fd);
00411 return 0;
00412 }
00413
00414
00415 static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
00416 {
00417 char vlan_ifname[IFNAMSIZ];
00418 char br_name[IFNAMSIZ];
00419 struct hostapd_vlan *vlan = hapd->conf->vlan;
00420 char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
00421
00422 while (vlan) {
00423 if (os_strcmp(ifname, vlan->ifname) == 0) {
00424
00425 os_snprintf(br_name, sizeof(br_name), "brvlan%d",
00426 vlan->vlan_id);
00427
00428 if (!br_addbr(br_name))
00429 vlan->clean |= DVLAN_CLEAN_BR;
00430
00431 ifconfig_up(br_name);
00432
00433 if (tagged_interface) {
00434
00435 if (!vlan_add(tagged_interface, vlan->vlan_id))
00436 vlan->clean |= DVLAN_CLEAN_VLAN;
00437
00438 os_snprintf(vlan_ifname, sizeof(vlan_ifname),
00439 "vlan%d", vlan->vlan_id);
00440
00441 if (!br_addif(br_name, vlan_ifname))
00442 vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
00443
00444 ifconfig_up(vlan_ifname);
00445 }
00446
00447 if (!br_addif(br_name, ifname))
00448 vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
00449
00450 ifconfig_up(ifname);
00451
00452 break;
00453 }
00454 vlan = vlan->next;
00455 }
00456 }
00457
00458
00459 static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
00460 {
00461 char vlan_ifname[IFNAMSIZ];
00462 char br_name[IFNAMSIZ];
00463 struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
00464 char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
00465 int numports;
00466
00467 first = prev = vlan;
00468
00469 while (vlan) {
00470 if (os_strcmp(ifname, vlan->ifname) == 0) {
00471 os_snprintf(br_name, sizeof(br_name), "brvlan%d",
00472 vlan->vlan_id);
00473
00474 if (tagged_interface) {
00475 os_snprintf(vlan_ifname, sizeof(vlan_ifname),
00476 "vlan%d", vlan->vlan_id);
00477
00478 numports = br_getnumports(br_name);
00479 if (numports == 1) {
00480 br_delif(br_name, vlan_ifname);
00481
00482 vlan_rem(vlan_ifname);
00483
00484 ifconfig_down(br_name);
00485 br_delbr(br_name);
00486 }
00487 }
00488
00489 if (vlan == first) {
00490 hapd->conf->vlan = vlan->next;
00491 } else {
00492 prev->next = vlan->next;
00493 }
00494 os_free(vlan);
00495
00496 break;
00497 }
00498 prev = vlan;
00499 vlan = vlan->next;
00500 }
00501 }
00502
00503
00504 static void
00505 vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
00506 struct hostapd_data *hapd)
00507 {
00508 struct ifinfomsg *ifi;
00509 int attrlen, nlmsg_len, rta_len;
00510 struct rtattr *attr;
00511
00512 if (len < sizeof(*ifi))
00513 return;
00514
00515 ifi = NLMSG_DATA(h);
00516
00517 nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
00518
00519 attrlen = h->nlmsg_len - nlmsg_len;
00520 if (attrlen < 0)
00521 return;
00522
00523 attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
00524
00525 rta_len = RTA_ALIGN(sizeof(struct rtattr));
00526 while (RTA_OK(attr, attrlen)) {
00527 char ifname[IFNAMSIZ + 1];
00528
00529 if (attr->rta_type == IFLA_IFNAME) {
00530 int n = attr->rta_len - rta_len;
00531 if (n < 0)
00532 break;
00533
00534 os_memset(ifname, 0, sizeof(ifname));
00535
00536 if ((size_t) n > sizeof(ifname))
00537 n = sizeof(ifname);
00538 os_memcpy(ifname, ((char *) attr) + rta_len, n);
00539
00540 if (del)
00541 vlan_dellink(ifname, hapd);
00542 else
00543 vlan_newlink(ifname, hapd);
00544 }
00545
00546 attr = RTA_NEXT(attr, attrlen);
00547 }
00548 }
00549
00550
00551 static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
00552 {
00553 char buf[8192];
00554 int left;
00555 struct sockaddr_nl from;
00556 socklen_t fromlen;
00557 struct nlmsghdr *h;
00558 struct hostapd_data *hapd = eloop_ctx;
00559
00560 fromlen = sizeof(from);
00561 left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
00562 (struct sockaddr *) &from, &fromlen);
00563 if (left < 0) {
00564 if (errno != EINTR && errno != EAGAIN)
00565 perror("recvfrom(netlink)");
00566 return;
00567 }
00568
00569 h = (struct nlmsghdr *) buf;
00570 while (left >= (int) sizeof(*h)) {
00571 int len, plen;
00572
00573 len = h->nlmsg_len;
00574 plen = len - sizeof(*h);
00575 if (len > left || plen < 0) {
00576 printf("Malformed netlink message: "
00577 "len=%d left=%d plen=%d", len, left, plen);
00578 break;
00579 }
00580
00581 switch (h->nlmsg_type) {
00582 case RTM_NEWLINK:
00583 vlan_read_ifnames(h, plen, 0, hapd);
00584 break;
00585 case RTM_DELLINK:
00586 vlan_read_ifnames(h, plen, 1, hapd);
00587 break;
00588 }
00589
00590 len = NLMSG_ALIGN(len);
00591 left -= len;
00592 h = (struct nlmsghdr *) ((char *) h + len);
00593 }
00594
00595 if (left > 0) {
00596 printf("%d extra bytes in the end of netlink message",
00597 left);
00598 }
00599 }
00600
00601
00602 static struct full_dynamic_vlan *
00603 full_dynamic_vlan_init(struct hostapd_data *hapd)
00604 {
00605 struct sockaddr_nl local;
00606 struct full_dynamic_vlan *priv;
00607
00608 priv = os_zalloc(sizeof(*priv));
00609 if (priv == NULL)
00610 return NULL;
00611
00612 vlan_set_name_type(VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
00613
00614 priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
00615 if (priv->s < 0) {
00616 perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
00617 os_free(priv);
00618 return NULL;
00619 }
00620
00621 os_memset(&local, 0, sizeof(local));
00622 local.nl_family = AF_NETLINK;
00623 local.nl_groups = RTMGRP_LINK;
00624 if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
00625 perror("bind(netlink)");
00626 close(priv->s);
00627 os_free(priv);
00628 return NULL;
00629 }
00630
00631 if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
00632 {
00633 close(priv->s);
00634 os_free(priv);
00635 return NULL;
00636 }
00637
00638 return priv;
00639 }
00640
00641
00642 static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
00643 {
00644 if (priv == NULL)
00645 return;
00646 eloop_unregister_read_sock(priv->s);
00647 close(priv->s);
00648 os_free(priv);
00649 }
00650 #endif
00651
00652
00653 int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
00654 struct hostapd_ssid *mssid, const char *dyn_vlan)
00655 {
00656 int i;
00657
00658 if (dyn_vlan == NULL)
00659 return 0;
00660
00661
00662
00663 for (i = 0; i < 4; i++) {
00664 if (mssid->wep.key[i] &&
00665 hostapd_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
00666 i == mssid->wep.idx, NULL, 0,
00667 mssid->wep.key[i], mssid->wep.len[i])) {
00668 printf("VLAN: Could not set WEP encryption for "
00669 "dynamic VLAN.\n");
00670 return -1;
00671 }
00672 }
00673
00674 return 0;
00675 }
00676
00677
00678 static int vlan_dynamic_add(struct hostapd_data *hapd,
00679 struct hostapd_vlan *vlan)
00680 {
00681 while (vlan) {
00682 if (vlan->vlan_id != VLAN_ID_WILDCARD &&
00683 hostapd_if_add(hapd, HOSTAPD_IF_VLAN, vlan->ifname, NULL))
00684 {
00685 if (errno != EEXIST) {
00686 printf("Could not add VLAN iface: %s: %s\n",
00687 vlan->ifname, strerror(errno));
00688 return -1;
00689 }
00690 }
00691
00692 vlan = vlan->next;
00693 }
00694
00695 return 0;
00696 }
00697
00698
00699 static void vlan_dynamic_remove(struct hostapd_data *hapd,
00700 struct hostapd_vlan *vlan)
00701 {
00702 struct hostapd_vlan *next;
00703
00704 while (vlan) {
00705 next = vlan->next;
00706
00707 if (vlan->vlan_id != VLAN_ID_WILDCARD &&
00708 hostapd_if_remove(hapd, HOSTAPD_IF_VLAN, vlan->ifname,
00709 NULL)) {
00710 printf("Could not remove VLAN iface: %s: %s\n",
00711 vlan->ifname, strerror(errno));
00712 }
00713 #ifdef CONFIG_FULL_DYNAMIC_VLAN
00714 if (vlan->clean)
00715 vlan_dellink(vlan->ifname, hapd);
00716 #endif
00717
00718 vlan = next;
00719 }
00720 }
00721
00722
00723 int vlan_init(struct hostapd_data *hapd)
00724 {
00725 if (vlan_dynamic_add(hapd, hapd->conf->vlan))
00726 return -1;
00727
00728 #ifdef CONFIG_FULL_DYNAMIC_VLAN
00729 hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
00730 #endif
00731
00732 return 0;
00733 }
00734
00735
00736 void vlan_deinit(struct hostapd_data *hapd)
00737 {
00738 vlan_dynamic_remove(hapd, hapd->conf->vlan);
00739
00740 #ifdef CONFIG_FULL_DYNAMIC_VLAN
00741 full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
00742 #endif
00743 }
00744
00745
00746 int vlan_reconfig(struct hostapd_data *hapd, struct hostapd_config *oldconf,
00747 struct hostapd_bss_config *oldbss)
00748 {
00749 vlan_dynamic_remove(hapd, oldbss->vlan);
00750 if (vlan_dynamic_add(hapd, hapd->conf->vlan))
00751 return -1;
00752
00753 return 0;
00754 }
00755
00756
00757 struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
00758 struct hostapd_vlan *vlan,
00759 int vlan_id)
00760 {
00761 struct hostapd_vlan *n;
00762 char *ifname, *pos;
00763
00764 if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
00765 vlan->vlan_id != VLAN_ID_WILDCARD)
00766 return NULL;
00767
00768 ifname = os_strdup(vlan->ifname);
00769 if (ifname == NULL)
00770 return NULL;
00771 pos = os_strchr(ifname, '#');
00772 if (pos == NULL) {
00773 os_free(ifname);
00774 return NULL;
00775 }
00776 *pos++ = '\0';
00777
00778 n = os_zalloc(sizeof(*n));
00779 if (n == NULL) {
00780 os_free(ifname);
00781 return NULL;
00782 }
00783
00784 n->vlan_id = vlan_id;
00785 n->dynamic_vlan = 1;
00786
00787 os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
00788 pos);
00789 os_free(ifname);
00790
00791 if (hostapd_if_add(hapd, HOSTAPD_IF_VLAN, n->ifname, NULL)) {
00792 os_free(n);
00793 return NULL;
00794 }
00795
00796 n->next = hapd->conf->vlan;
00797 hapd->conf->vlan = n;
00798
00799 return n;
00800 }
00801
00802
00803 int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
00804 {
00805 struct hostapd_vlan *vlan;
00806
00807 if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
00808 return 1;
00809
00810 vlan = hapd->conf->vlan;
00811 while (vlan) {
00812 if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
00813 vlan->dynamic_vlan--;
00814 break;
00815 }
00816 vlan = vlan->next;
00817 }
00818
00819 if (vlan == NULL)
00820 return 1;
00821
00822 if (vlan->dynamic_vlan == 0)
00823 hostapd_if_remove(hapd, HOSTAPD_IF_VLAN, vlan->ifname, NULL);
00824
00825 return 0;
00826 }
00827