LCOV - code coverage report
Current view: top level - src/ap - vlan_full.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1475438200 Lines: 303 367 82.6 %
Date: 2016-10-02 Functions: 19 19 100.0 %

          Line data    Source code
       1             : /*
       2             :  * hostapd / VLAN initialization - full dynamic VLAN
       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             : #include <net/if.h>
      13             : /* Avoid conflicts due to NetBSD net/if.h if_type define with driver.h */
      14             : #undef if_type
      15             : #include <sys/ioctl.h>
      16             : 
      17             : #include "utils/common.h"
      18             : #include "drivers/priv_netlink.h"
      19             : #include "common/linux_bridge.h"
      20             : #include "common/linux_vlan.h"
      21             : #include "utils/eloop.h"
      22             : #include "hostapd.h"
      23             : #include "ap_config.h"
      24             : #include "ap_drv_ops.h"
      25             : #include "wpa_auth.h"
      26             : #include "vlan_init.h"
      27             : #include "vlan_util.h"
      28             : 
      29             : 
      30             : struct full_dynamic_vlan {
      31             :         int s; /* socket on which to listen for new/removed interfaces. */
      32             : };
      33             : 
      34             : #define DVLAN_CLEAN_BR         0x1
      35             : #define DVLAN_CLEAN_VLAN       0x2
      36             : #define DVLAN_CLEAN_VLAN_PORT  0x4
      37             : 
      38             : struct dynamic_iface {
      39             :         char ifname[IFNAMSIZ + 1];
      40             :         int usage;
      41             :         int clean;
      42             :         struct dynamic_iface *next;
      43             : };
      44             : 
      45             : 
      46             : /* Increment ref counter for ifname and add clean flag.
      47             :  * If not in list, add it only if some flags are given.
      48             :  */
      49          55 : static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
      50             :                           int clean)
      51             : {
      52             :         struct dynamic_iface *next, **dynamic_ifaces;
      53             :         struct hapd_interfaces *interfaces;
      54             : 
      55          55 :         interfaces = hapd->iface->interfaces;
      56          55 :         dynamic_ifaces = &interfaces->vlan_priv;
      57             : 
      58          86 :         for (next = *dynamic_ifaces; next; next = next->next) {
      59          39 :                 if (os_strcmp(ifname, next->ifname) == 0)
      60           8 :                         break;
      61             :         }
      62             : 
      63          55 :         if (next) {
      64           8 :                 next->usage++;
      65           8 :                 next->clean |= clean;
      66           8 :                 return;
      67             :         }
      68             : 
      69          47 :         if (!clean)
      70          10 :                 return;
      71             : 
      72          37 :         next = os_zalloc(sizeof(*next));
      73          37 :         if (!next)
      74           0 :                 return;
      75          37 :         os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
      76          37 :         next->usage = 1;
      77          37 :         next->clean = clean;
      78          37 :         next->next = *dynamic_ifaces;
      79          37 :         *dynamic_ifaces = next;
      80             : }
      81             : 
      82             : 
      83             : /* Decrement reference counter for given ifname.
      84             :  * Return clean flag iff reference counter was decreased to zero, else zero
      85             :  */
      86          55 : static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
      87             : {
      88          55 :         struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
      89             :         struct hapd_interfaces *interfaces;
      90             :         int clean;
      91             : 
      92          55 :         interfaces = hapd->iface->interfaces;
      93          55 :         dynamic_ifaces = &interfaces->vlan_priv;
      94             : 
      95          74 :         for (next = *dynamic_ifaces; next; next = next->next) {
      96          64 :                 if (os_strcmp(ifname, next->ifname) == 0)
      97          45 :                         break;
      98          19 :                 prev = next;
      99             :         }
     100             : 
     101          55 :         if (!next)
     102          10 :                 return 0;
     103             : 
     104          45 :         next->usage--;
     105          45 :         if (next->usage)
     106           8 :                 return 0;
     107             : 
     108          37 :         if (prev)
     109           8 :                 prev->next = next->next;
     110             :         else
     111          29 :                 *dynamic_ifaces = next->next;
     112          37 :         clean = next->clean;
     113          37 :         os_free(next);
     114             : 
     115          37 :         return clean;
     116             : }
     117             : 
     118             : 
     119          37 : static int ifconfig_down(const char *if_name)
     120             : {
     121          37 :         wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
     122          37 :         return ifconfig_helper(if_name, 0);
     123             : }
     124             : 
     125             : 
     126             : /* This value should be 256 ONLY. If it is something else, then hostapd
     127             :  * might crash!, as this value has been hard-coded in 2.4.x kernel
     128             :  * bridging code.
     129             :  */
     130             : #define MAX_BR_PORTS                    256
     131             : 
     132          52 : static int br_delif(const char *br_name, const char *if_name)
     133             : {
     134             :         int fd;
     135             :         struct ifreq ifr;
     136             :         unsigned long args[2];
     137             :         int if_index;
     138             : 
     139          52 :         wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
     140          52 :         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
     141           0 :                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
     142           0 :                            "failed: %s", __func__, strerror(errno));
     143           0 :                 return -1;
     144             :         }
     145             : 
     146          52 :         if_index = if_nametoindex(if_name);
     147             : 
     148          52 :         if (if_index == 0) {
     149          42 :                 wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
     150             :                            "interface index for '%s'",
     151             :                            __func__, if_name);
     152          42 :                 close(fd);
     153          42 :                 return -1;
     154             :         }
     155             : 
     156          10 :         args[0] = BRCTL_DEL_IF;
     157          10 :         args[1] = if_index;
     158             : 
     159          10 :         os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
     160          10 :         ifr.ifr_data = (void *) args;
     161             : 
     162          10 :         if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
     163             :                 /* No error if interface already removed. */
     164           4 :                 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
     165             :                            "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
     166           4 :                            "%s", __func__, br_name, if_name, strerror(errno));
     167           4 :                 close(fd);
     168           4 :                 return -1;
     169             :         }
     170             : 
     171           6 :         close(fd);
     172           6 :         return 0;
     173             : }
     174             : 
     175             : 
     176             : /*
     177             :         Add interface 'if_name' to the bridge 'br_name'
     178             : 
     179             :         returns -1 on error
     180             :         returns 1 if the interface is already part of the bridge
     181             :         returns 0 otherwise
     182             : */
     183          58 : static int br_addif(const char *br_name, const char *if_name)
     184             : {
     185             :         int fd;
     186             :         struct ifreq ifr;
     187             :         unsigned long args[2];
     188             :         int if_index;
     189             : 
     190          58 :         wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
     191          58 :         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
     192           0 :                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
     193           0 :                            "failed: %s", __func__, strerror(errno));
     194           0 :                 return -1;
     195             :         }
     196             : 
     197          58 :         if_index = if_nametoindex(if_name);
     198             : 
     199          58 :         if (if_index == 0) {
     200           2 :                 wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
     201             :                            "interface index for '%s'",
     202             :                            __func__, if_name);
     203           2 :                 close(fd);
     204           2 :                 return -1;
     205             :         }
     206             : 
     207          56 :         args[0] = BRCTL_ADD_IF;
     208          56 :         args[1] = if_index;
     209             : 
     210          56 :         os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
     211          56 :         ifr.ifr_data = (void *) args;
     212             : 
     213          56 :         if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
     214           4 :                 if (errno == EBUSY) {
     215             :                         /* The interface is already added. */
     216           4 :                         close(fd);
     217           4 :                         return 1;
     218             :                 }
     219             : 
     220           0 :                 wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
     221             :                            "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
     222           0 :                            "%s", __func__, br_name, if_name, strerror(errno));
     223           0 :                 close(fd);
     224           0 :                 return -1;
     225             :         }
     226             : 
     227          52 :         close(fd);
     228          52 :         return 0;
     229             : }
     230             : 
     231             : 
     232          28 : static int br_delbr(const char *br_name)
     233             : {
     234             :         int fd;
     235             :         unsigned long arg[2];
     236             : 
     237          28 :         wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
     238          28 :         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
     239           0 :                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
     240           0 :                            "failed: %s", __func__, strerror(errno));
     241           0 :                 return -1;
     242             :         }
     243             : 
     244          28 :         arg[0] = BRCTL_DEL_BRIDGE;
     245          28 :         arg[1] = (unsigned long) br_name;
     246             : 
     247          28 :         if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
     248             :                 /* No error if bridge already removed. */
     249           0 :                 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
     250           0 :                            "%s: %s", __func__, br_name, strerror(errno));
     251           0 :                 close(fd);
     252           0 :                 return -1;
     253             :         }
     254             : 
     255          28 :         close(fd);
     256          28 :         return 0;
     257             : }
     258             : 
     259             : 
     260             : /*
     261             :         Add a bridge with the name 'br_name'.
     262             : 
     263             :         returns -1 on error
     264             :         returns 1 if the bridge already exists
     265             :         returns 0 otherwise
     266             : */
     267          40 : static int br_addbr(const char *br_name)
     268             : {
     269             :         int fd;
     270             :         unsigned long arg[4];
     271             :         struct ifreq ifr;
     272             : 
     273          40 :         wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
     274          40 :         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
     275           0 :                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
     276           0 :                            "failed: %s", __func__, strerror(errno));
     277           0 :                 return -1;
     278             :         }
     279             : 
     280          40 :         arg[0] = BRCTL_ADD_BRIDGE;
     281          40 :         arg[1] = (unsigned long) br_name;
     282             : 
     283          40 :         if (ioctl(fd, SIOCGIFBR, arg) < 0) {
     284          12 :                 if (errno == EEXIST) {
     285             :                         /* The bridge is already added. */
     286          12 :                         close(fd);
     287          12 :                         return 1;
     288             :                 } else {
     289           0 :                         wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
     290             :                                    "failed for %s: %s",
     291           0 :                                    __func__, br_name, strerror(errno));
     292           0 :                         close(fd);
     293           0 :                         return -1;
     294             :                 }
     295             :         }
     296             : 
     297             :         /* Decrease forwarding delay to avoid EAPOL timeouts. */
     298          28 :         os_memset(&ifr, 0, sizeof(ifr));
     299          28 :         os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
     300          28 :         arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
     301          28 :         arg[1] = 1;
     302          28 :         arg[2] = 0;
     303          28 :         arg[3] = 0;
     304          28 :         ifr.ifr_data = (char *) &arg;
     305          28 :         if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
     306           0 :                 wpa_printf(MSG_ERROR, "VLAN: %s: "
     307             :                            "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
     308           0 :                            "%s: %s", __func__, br_name, strerror(errno));
     309             :                 /* Continue anyway */
     310             :         }
     311             : 
     312          28 :         close(fd);
     313          28 :         return 0;
     314             : }
     315             : 
     316             : 
     317          28 : static int br_getnumports(const char *br_name)
     318             : {
     319             :         int fd;
     320             :         int i;
     321          28 :         int port_cnt = 0;
     322             :         unsigned long arg[4];
     323             :         int ifindices[MAX_BR_PORTS];
     324             :         struct ifreq ifr;
     325             : 
     326          28 :         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
     327           0 :                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
     328           0 :                            "failed: %s", __func__, strerror(errno));
     329           0 :                 return -1;
     330             :         }
     331             : 
     332          28 :         arg[0] = BRCTL_GET_PORT_LIST;
     333          28 :         arg[1] = (unsigned long) ifindices;
     334          28 :         arg[2] = MAX_BR_PORTS;
     335          28 :         arg[3] = 0;
     336             : 
     337          28 :         os_memset(ifindices, 0, sizeof(ifindices));
     338          28 :         os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
     339          28 :         ifr.ifr_data = (void *) arg;
     340             : 
     341          28 :         if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
     342           0 :                 wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
     343             :                            "failed for %s: %s",
     344           0 :                            __func__, br_name, strerror(errno));
     345           0 :                 close(fd);
     346           0 :                 return -1;
     347             :         }
     348             : 
     349        7168 :         for (i = 1; i < MAX_BR_PORTS; i++) {
     350        7140 :                 if (ifindices[i] > 0) {
     351           0 :                         port_cnt++;
     352             :                 }
     353             :         }
     354             : 
     355          28 :         close(fd);
     356          28 :         return port_cnt;
     357             : }
     358             : 
     359             : 
     360          15 : static void vlan_newlink_tagged(int vlan_naming, const char *tagged_interface,
     361             :                                 const char *br_name, int vid,
     362             :                                 struct hostapd_data *hapd)
     363             : {
     364             :         char vlan_ifname[IFNAMSIZ];
     365             :         int clean;
     366             : 
     367          15 :         if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
     368          13 :                 os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
     369             :                             tagged_interface, vid);
     370             :         else
     371           2 :                 os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
     372             : 
     373          15 :         clean = 0;
     374          15 :         ifconfig_up(tagged_interface);
     375          15 :         if (!vlan_add(tagged_interface, vid, vlan_ifname))
     376           9 :                 clean |= DVLAN_CLEAN_VLAN;
     377             : 
     378          15 :         if (!br_addif(br_name, vlan_ifname))
     379           9 :                 clean |= DVLAN_CLEAN_VLAN_PORT;
     380             : 
     381          15 :         dyn_iface_get(hapd, vlan_ifname, clean);
     382             : 
     383          15 :         ifconfig_up(vlan_ifname);
     384          15 : }
     385             : 
     386             : 
     387          80 : static void vlan_bridge_name(char *br_name, struct hostapd_data *hapd, int vid)
     388             : {
     389          80 :         char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
     390             : 
     391          80 :         if (hapd->conf->vlan_bridge[0]) {
     392          16 :                 os_snprintf(br_name, IFNAMSIZ, "%s%d",
     393          16 :                             hapd->conf->vlan_bridge, vid);
     394          64 :         } else if (tagged_interface) {
     395           4 :                 os_snprintf(br_name, IFNAMSIZ, "br%s.%d",
     396             :                             tagged_interface, vid);
     397             :         } else {
     398          60 :                 os_snprintf(br_name, IFNAMSIZ, "brvlan%d", vid);
     399             :         }
     400          80 : }
     401             : 
     402             : 
     403          40 : static void vlan_get_bridge(const char *br_name, struct hostapd_data *hapd,
     404             :                             int vid)
     405             : {
     406          40 :         char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
     407          40 :         int vlan_naming = hapd->conf->ssid.vlan_naming;
     408             : 
     409          40 :         dyn_iface_get(hapd, br_name, br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
     410             : 
     411          40 :         ifconfig_up(br_name);
     412             : 
     413          40 :         if (tagged_interface)
     414          10 :                 vlan_newlink_tagged(vlan_naming, tagged_interface, br_name,
     415             :                                     vid, hapd);
     416          40 : }
     417             : 
     418             : 
     419       42267 : void vlan_newlink(const char *ifname, struct hostapd_data *hapd)
     420             : {
     421             :         char br_name[IFNAMSIZ];
     422             :         struct hostapd_vlan *vlan;
     423             :         int untagged, *tagged, i, notempty;
     424             : 
     425       42267 :         wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
     426             : 
     427       92338 :         for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
     428        6044 :                 if (vlan->configured ||
     429        2091 :                     os_strcmp(ifname, vlan->ifname) != 0)
     430        3902 :                         continue;
     431          51 :                 break;
     432             :         }
     433       42267 :         if (!vlan)
     434       84483 :                 return;
     435             : 
     436          51 :         vlan->configured = 1;
     437             : 
     438          51 :         notempty = vlan->vlan_desc.notempty;
     439          51 :         untagged = vlan->vlan_desc.untagged;
     440          51 :         tagged = vlan->vlan_desc.tagged;
     441             : 
     442          51 :         if (!notempty) {
     443             :                 /* Non-VLAN STA */
     444          20 :                 if (hapd->conf->bridge[0] &&
     445           8 :                     !br_addif(hapd->conf->bridge, ifname))
     446           8 :                         vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
     447          39 :         } else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
     448          35 :                 vlan_bridge_name(br_name, hapd, untagged);
     449             : 
     450          35 :                 vlan_get_bridge(br_name, hapd, untagged);
     451             : 
     452          35 :                 if (!br_addif(br_name, ifname))
     453          35 :                         vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
     454             :         }
     455             : 
     456          56 :         for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
     457          10 :                 if (tagged[i] == untagged ||
     458          10 :                     tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
     459           0 :                     (i > 0 && tagged[i] == tagged[i - 1]))
     460           0 :                         continue;
     461           5 :                 vlan_bridge_name(br_name, hapd, tagged[i]);
     462           5 :                 vlan_get_bridge(br_name, hapd, tagged[i]);
     463           5 :                 vlan_newlink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
     464           5 :                                     ifname, br_name, tagged[i], hapd);
     465             :         }
     466             : 
     467          51 :         ifconfig_up(ifname);
     468             : }
     469             : 
     470             : 
     471          15 : static void vlan_dellink_tagged(int vlan_naming, const char *tagged_interface,
     472             :                                 const char *br_name, int vid,
     473             :                                 struct hostapd_data *hapd)
     474             : {
     475             :         char vlan_ifname[IFNAMSIZ];
     476             :         int clean;
     477             : 
     478          15 :         if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
     479          13 :                 os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
     480             :                             tagged_interface, vid);
     481             :         else
     482           2 :                 os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
     483             : 
     484          15 :         clean = dyn_iface_put(hapd, vlan_ifname);
     485             : 
     486          15 :         if (clean & DVLAN_CLEAN_VLAN_PORT)
     487           9 :                 br_delif(br_name, vlan_ifname);
     488             : 
     489          15 :         if (clean & DVLAN_CLEAN_VLAN) {
     490           9 :                 ifconfig_down(vlan_ifname);
     491           9 :                 vlan_rem(vlan_ifname);
     492             :         }
     493          15 : }
     494             : 
     495             : 
     496          40 : static void vlan_put_bridge(const char *br_name, struct hostapd_data *hapd,
     497             :                             int vid)
     498             : {
     499             :         int clean;
     500          40 :         char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
     501          40 :         int vlan_naming = hapd->conf->ssid.vlan_naming;
     502             : 
     503          40 :         if (tagged_interface)
     504          10 :                 vlan_dellink_tagged(vlan_naming, tagged_interface, br_name,
     505             :                                     vid, hapd);
     506             : 
     507          40 :         clean = dyn_iface_put(hapd, br_name);
     508          40 :         if ((clean & DVLAN_CLEAN_BR) && br_getnumports(br_name) == 0) {
     509          28 :                 ifconfig_down(br_name);
     510          28 :                 br_delbr(br_name);
     511             :         }
     512          40 : }
     513             : 
     514             : 
     515         500 : void vlan_dellink(const char *ifname, struct hostapd_data *hapd)
     516             : {
     517         500 :         struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
     518             : 
     519         500 :         wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
     520             : 
     521         500 :         first = prev = vlan;
     522             : 
     523        1241 :         while (vlan) {
     524         292 :                 if (os_strcmp(ifname, vlan->ifname) != 0) {
     525         241 :                         prev = vlan;
     526         241 :                         vlan = vlan->next;
     527         241 :                         continue;
     528             :                 }
     529          51 :                 break;
     530             :         }
     531         500 :         if (!vlan)
     532         949 :                 return;
     533             : 
     534          51 :         if (vlan->configured) {
     535          51 :                 int notempty = vlan->vlan_desc.notempty;
     536          51 :                 int untagged = vlan->vlan_desc.untagged;
     537          51 :                 int *tagged = vlan->vlan_desc.tagged;
     538             :                 char br_name[IFNAMSIZ];
     539             :                 int i;
     540             : 
     541          56 :                 for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
     542          10 :                         if (tagged[i] == untagged ||
     543          10 :                             tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
     544           0 :                             (i > 0 && tagged[i] == tagged[i - 1]))
     545           0 :                                 continue;
     546           5 :                         vlan_bridge_name(br_name, hapd, tagged[i]);
     547           5 :                         vlan_dellink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
     548           5 :                                             ifname, br_name, tagged[i], hapd);
     549           5 :                         vlan_put_bridge(br_name, hapd, tagged[i]);
     550             :                 }
     551             : 
     552          51 :                 if (!notempty) {
     553             :                         /* Non-VLAN STA */
     554          20 :                         if (hapd->conf->bridge[0] &&
     555           8 :                             (vlan->clean & DVLAN_CLEAN_WLAN_PORT))
     556           8 :                                 br_delif(hapd->conf->bridge, ifname);
     557          39 :                 } else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
     558          35 :                         vlan_bridge_name(br_name, hapd, untagged);
     559             : 
     560          35 :                         if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
     561          35 :                                 br_delif(br_name, vlan->ifname);
     562             : 
     563          35 :                         vlan_put_bridge(br_name, hapd, untagged);
     564             :                 }
     565             :         }
     566             : 
     567             :         /*
     568             :          * Ensure this VLAN interface is actually removed even if
     569             :          * NEWLINK message is only received later.
     570             :          */
     571          51 :         if (if_nametoindex(vlan->ifname) && vlan_if_remove(hapd, vlan))
     572           0 :                 wpa_printf(MSG_ERROR,
     573             :                            "VLAN: Could not remove VLAN iface: %s: %s",
     574           0 :                            vlan->ifname, strerror(errno));
     575             : 
     576          51 :         if (vlan == first)
     577          29 :                 hapd->conf->vlan = vlan->next;
     578             :         else
     579          22 :                 prev->next = vlan->next;
     580             : 
     581          51 :         os_free(vlan);
     582             : }
     583             : 
     584             : 
     585             : static void
     586       42776 : vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
     587             :                   struct hostapd_data *hapd)
     588             : {
     589             :         struct ifinfomsg *ifi;
     590             :         int attrlen, nlmsg_len, rta_len;
     591             :         struct rtattr *attr;
     592             :         char ifname[IFNAMSIZ + 1];
     593             : 
     594       42776 :         if (len < sizeof(*ifi))
     595          66 :                 return;
     596             : 
     597       42776 :         ifi = NLMSG_DATA(h);
     598             : 
     599       42776 :         nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
     600             : 
     601       42776 :         attrlen = h->nlmsg_len - nlmsg_len;
     602       42776 :         if (attrlen < 0)
     603           0 :                 return;
     604             : 
     605       42776 :         attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
     606             : 
     607       42776 :         os_memset(ifname, 0, sizeof(ifname));
     608       42776 :         rta_len = RTA_ALIGN(sizeof(struct rtattr));
     609      579773 :         while (RTA_OK(attr, attrlen)) {
     610      494221 :                 if (attr->rta_type == IFLA_IFNAME) {
     611       42776 :                         int n = attr->rta_len - rta_len;
     612       42776 :                         if (n < 0)
     613           0 :                                 break;
     614             : 
     615       42776 :                         if ((size_t) n >= sizeof(ifname))
     616           0 :                                 n = sizeof(ifname) - 1;
     617       42776 :                         os_memcpy(ifname, ((char *) attr) + rta_len, n);
     618             : 
     619             :                 }
     620             : 
     621      494221 :                 attr = RTA_NEXT(attr, attrlen);
     622             :         }
     623             : 
     624       42776 :         if (!ifname[0])
     625           0 :                 return;
     626       42776 :         if (del && if_nametoindex(ifname)) {
     627             :                  /* interface still exists, race condition ->
     628             :                   * iface has just been recreated */
     629          66 :                 return;
     630             :         }
     631             : 
     632      213550 :         wpa_printf(MSG_DEBUG,
     633             :                    "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
     634             :                    del ? "DEL" : "NEW",
     635       42710 :                    ifi->ifi_index, ifname, ifi->ifi_family, ifi->ifi_flags,
     636       42710 :                    (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
     637       42710 :                    (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
     638       42710 :                    (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
     639       42710 :                    (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
     640             : 
     641       42710 :         if (del)
     642         449 :                 vlan_dellink(ifname, hapd);
     643             :         else
     644       42261 :                 vlan_newlink(ifname, hapd);
     645             : }
     646             : 
     647             : 
     648       42776 : static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
     649             : {
     650             :         char buf[8192];
     651             :         int left;
     652             :         struct sockaddr_nl from;
     653             :         socklen_t fromlen;
     654             :         struct nlmsghdr *h;
     655       42776 :         struct hostapd_data *hapd = eloop_ctx;
     656             : 
     657       42776 :         fromlen = sizeof(from);
     658       42776 :         left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
     659             :                         (struct sockaddr *) &from, &fromlen);
     660       42776 :         if (left < 0) {
     661           0 :                 if (errno != EINTR && errno != EAGAIN)
     662           0 :                         wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
     663           0 :                                    __func__, strerror(errno));
     664       42776 :                 return;
     665             :         }
     666             : 
     667       42776 :         h = (struct nlmsghdr *) buf;
     668      128328 :         while (NLMSG_OK(h, left)) {
     669             :                 int len, plen;
     670             : 
     671       42776 :                 len = h->nlmsg_len;
     672       42776 :                 plen = len - sizeof(*h);
     673       42776 :                 if (len > left || plen < 0) {
     674           0 :                         wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
     675             :                                    "message: len=%d left=%d plen=%d",
     676             :                                    len, left, plen);
     677           0 :                         break;
     678             :                 }
     679             : 
     680       42776 :                 switch (h->nlmsg_type) {
     681             :                 case RTM_NEWLINK:
     682       42261 :                         vlan_read_ifnames(h, plen, 0, hapd);
     683       42261 :                         break;
     684             :                 case RTM_DELLINK:
     685         515 :                         vlan_read_ifnames(h, plen, 1, hapd);
     686         515 :                         break;
     687             :                 }
     688             : 
     689       42776 :                 h = NLMSG_NEXT(h, left);
     690             :         }
     691             : 
     692       42776 :         if (left > 0) {
     693           0 :                 wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
     694             :                            "netlink message", __func__, left);
     695             :         }
     696             : }
     697             : 
     698             : 
     699             : struct full_dynamic_vlan *
     700        2024 : full_dynamic_vlan_init(struct hostapd_data *hapd)
     701             : {
     702             :         struct sockaddr_nl local;
     703             :         struct full_dynamic_vlan *priv;
     704             : 
     705        2024 :         priv = os_zalloc(sizeof(*priv));
     706        2024 :         if (priv == NULL)
     707           0 :                 return NULL;
     708             : 
     709        2024 :         vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
     710             :                            DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
     711             :                            VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
     712             :                            VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
     713             : 
     714        2024 :         priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
     715        2024 :         if (priv->s < 0) {
     716           0 :                 wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
     717             :                            "NETLINK_ROUTE) failed: %s",
     718           0 :                            __func__, strerror(errno));
     719           0 :                 os_free(priv);
     720           0 :                 return NULL;
     721             :         }
     722             : 
     723        2024 :         os_memset(&local, 0, sizeof(local));
     724        2024 :         local.nl_family = AF_NETLINK;
     725        2024 :         local.nl_groups = RTMGRP_LINK;
     726        2024 :         if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
     727           0 :                 wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
     728           0 :                            __func__, strerror(errno));
     729           0 :                 close(priv->s);
     730           0 :                 os_free(priv);
     731           0 :                 return NULL;
     732             :         }
     733             : 
     734        2024 :         if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
     735             :         {
     736           0 :                 close(priv->s);
     737           0 :                 os_free(priv);
     738           0 :                 return NULL;
     739             :         }
     740             : 
     741        2024 :         return priv;
     742             : }
     743             : 
     744             : 
     745        2046 : void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
     746             : {
     747        2046 :         if (priv == NULL)
     748        2068 :                 return;
     749        2024 :         eloop_unregister_read_sock(priv->s);
     750        2024 :         close(priv->s);
     751        2024 :         os_free(priv);
     752             : }

Generated by: LCOV version 1.10