LCOV - code coverage report
Current view: top level - src/ap - vlan_init.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1443382998 Lines: 391 513 76.2 %
Date: 2015-09-27 Functions: 26 26 100.0 %

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

Generated by: LCOV version 1.10