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


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:36