Cumulative patch from commit 077dcfb8c48d2509a6e116c0de3ad57d2fbfe4fe
077dcfb AP: Debug print management frame TX result
ca911d6 MBO: Parse non-preferred channel list on the AP
3f48274 WNM: Fix a memory leak on AP error path
f5ca176 VLAN: Fix vlan_compare() for tagged VLANs
1260564 hostapd_cli: Add support for RAW command
940491c MBO: Mandate use of PMF for WPA2+MBO association (STA)
4c57228 MBO: Mandate use of PMF for WPA2+MBO association (AP)
8dd49f0 MBO: Update STA cellular data capability based on WNM Notification
6332aaf MBO: Track STA cellular data capability from association request
f3cb7a6 WNM: Minimal processing for WNM Notification Request frames on AP
e578343 MBO: Indicate WNM-Notification support on AP when MBO is enabled
990b7b6 Simplify hostapd_build_ap_extra_ies() with helper functions
d010048 MBO: Expire non-matching bss_tmp_disallowed entries as part of check
f4c74e1 MBO: Parse MBO IE in ieee802_11_parse_elems()
016082e MBO: Send WNM-Notification when cellular capabilities change
c0e2a17 hostapd: Add MBO IE to BSS Transition Management Request frame
fb9a1c3 hostapd: Add MBO IE to Beacon, Probe Response, Association Response
c484b19 Move Hotspot 2.0 element in (Re)Association Request frames
a0c38e5 Re-order elements in (Re)Association Request frames
9a493fa WNM: Add candidate list to BSS transition query
84d1c0f WNM: Add candidate list to BSS transition response
cf11ab7 utils: Derive phy type by frequency and bandwidth
c8082d2 MBO: Add MBO IE to BSS Transition Management Response frame
dd59990 MBO: Parse MBO IE in BSS Transition Management Request frames
5e57ba2 MBO: Add Supported Operating Classes element to Association Request
7d46f58 MBO: Add global operating class definitions
cb06cf3 MBO: Prevent association to APs that explicitly disallow this
c5d193d MBO: Add cellular capability to MBO IE
2d5b861 MBO: Send MBO WNM-Notification Request frames to notify changes
92c6e2e MBO: Implement MBO non-preferred channel report in Association Request
facf2c7 MBO: Add non-preferred channel configuration in wpa_supplicant
425dd78 MBO: Add Multi Band Operation definitions
a159958 ndis: Use the new get_ie() helper to avoid duplicated code
231b04b utils: Share a single helper function to get IE by ID
ea69d97 wpa_supplicant: Share a single get_mode() implementation
75cc211 VLAN: Check vlan_desc validity in a failure debug print
43022ab Use 64-bit TX/RX byte counters for statistics
3f81ac0 AP: Set STA assoc flag in the driver before sending Assoc Resp frame
bb598c3 AP: Add support for full station state
dc55b6b nl80211: Add support for full station state operations
5558b99 EAP-FAST peer: Remove fixed return value from eap_fast_parse_phase1()
4b16c15 EAP-pwd server: Use os_get_random() for unpredictable token
239952b DFS: Remove the os_random() fallback
98a516e WPS: Use only os_get_random() for PIN generation
f441e5a Use os_get_random() for Shared Key authentication challenge
8c676b5 Add RADIUS Service-Type attribute with a value of Framed
09d96de mesh: Drop Authentication frames from BLOCKED STA
70c9396 SAE: Fix PMKID calculation for PMKSA cache
1492fbb Print Acct-Session-Id and Acct-Multi-Session-Id 64-bit values
e21ceca kqueue: Use 0 instead of NULL for udata
640b0b9 ctype functions require an unsigned char
a5a3efc Fix compile on NetBSD for vlan
a084c24 wired: Fix compile on NetBSD for wired driver
634e2e2 Add CONFIG_ELOOP_KQUEUE to defconfig
99a94f5 nl80211: Avoid wpa_printf %s call with NULL pointer in set_param()
ba91e92 wpa_supplicant: Parse ifname argument from DATA_TEST_CONFIG
8be640b VLAN: Add per-STA vif option
d0bdc96 VLAN: Actually add tagged VLANs to AP_VLAN
f9c0018 VLAN: Factor out per-vid code in newlink/dellink
8e44c19 radius: Add tagged VLAN parsing
1889af2 VLAN: Separate station grouping and uplink configuration
3a583e0 OpenSSL: Fix PKCS#12 parsing of extra certificates with OpenSSL 1.0.1
ddd0032 wpa_cli: Clean up logical operation
24c382a TDLS: Clean up os_memcmp use
6136d43 trace: Free symbols on program exit
8bcf8de OpenSSL: Fix memory leak in PKCS12 additional certificate parsing
03e3ddf OpenSSL: Fix memory leak in HMAC_CTX compatibility wrapper function
d9a0f69 OpenSSL: Fix memory leak in OCSP parsing
29bc76e OpenSSL: Do not use library init/deinit functions with 1.1.0
0f09637 OpenSSL: Fix memory leak in subjectAltName parsing
e60913b curl: Fix memory leak in subjectAltName parsing
6014890 OpenSSL: Fix memory leak with EVP_CIPHER_CTX_new()
99a1735 rfkill: Fix a memory leak
1f1e599 OpenSSL: Fix memory leak on error path
b907491 wpa_supplicant: Basic support for PBSS/PCP
86b5c40 nl80211: Basic support for PBSS/PCP
afa453a Sync with mac80211-next.git include/uapi/linux/nl80211.h
d1d8a2b EAP peer: Simplify buildNotify return
1314bc1 Clean up EAP peer PCSC identity functions
Change-Id: I9db475a2a4ebc88d2ee024319ed59a850636bb16
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index e3df164..8eab6cb 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -9,13 +9,6 @@
*/
#include "utils/includes.h"
-#include <net/if.h>
-#include <sys/ioctl.h>
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-#include <linux/sockios.h>
-#include <linux/if_vlan.h>
-#include <linux/if_bridge.h>
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
#include "utils/common.h"
#include "hostapd.h"
@@ -25,6 +18,14 @@
#include "vlan_init.h"
#include "vlan_util.h"
+#include <net/if.h>
+#include <sys/ioctl.h>
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+#include <linux/sockios.h>
+#include <linux/if_vlan.h>
+#include <linux/if_bridge.h>
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
#ifdef CONFIG_FULL_DYNAMIC_VLAN
@@ -623,153 +624,228 @@
#endif /* CONFIG_VLAN_NETLINK */
-static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
+static void vlan_newlink_tagged(int vlan_naming, const char *tagged_interface,
+ const char *br_name, int vid,
+ struct hostapd_data *hapd)
{
char vlan_ifname[IFNAMSIZ];
- char br_name[IFNAMSIZ];
- struct hostapd_vlan *vlan = hapd->conf->vlan;
- char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
- int vlan_naming = hapd->conf->ssid.vlan_naming;
int clean;
- wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
+ if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+ os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
+ tagged_interface, vid);
+ else
+ os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
- while (vlan) {
- if (os_strcmp(ifname, vlan->ifname) == 0 && !vlan->configured) {
- vlan->configured = 1;
+ clean = 0;
+ ifconfig_up(tagged_interface);
+ if (!vlan_add(tagged_interface, vid, vlan_ifname))
+ clean |= DVLAN_CLEAN_VLAN;
- if (hapd->conf->vlan_bridge[0]) {
- os_snprintf(br_name, sizeof(br_name), "%s%d",
- hapd->conf->vlan_bridge,
- vlan->vlan_id);
- } else if (tagged_interface) {
- os_snprintf(br_name, sizeof(br_name),
- "br%s.%d", tagged_interface,
- vlan->vlan_id);
- } else {
- os_snprintf(br_name, sizeof(br_name),
- "brvlan%d", vlan->vlan_id);
- }
+ if (!br_addif(br_name, vlan_ifname))
+ clean |= DVLAN_CLEAN_VLAN_PORT;
- dyn_iface_get(hapd, br_name,
- br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
+ dyn_iface_get(hapd, vlan_ifname, clean);
- ifconfig_up(br_name);
+ ifconfig_up(vlan_ifname);
+}
- if (tagged_interface) {
- if (vlan_naming ==
- DYNAMIC_VLAN_NAMING_WITH_DEVICE)
- os_snprintf(vlan_ifname,
- sizeof(vlan_ifname),
- "%s.%d", tagged_interface,
- vlan->vlan_id);
- else
- os_snprintf(vlan_ifname,
- sizeof(vlan_ifname),
- "vlan%d", vlan->vlan_id);
- clean = 0;
- ifconfig_up(tagged_interface);
- if (!vlan_add(tagged_interface, vlan->vlan_id,
- vlan_ifname))
- clean |= DVLAN_CLEAN_VLAN;
+static void vlan_bridge_name(char *br_name, struct hostapd_data *hapd, int vid)
+{
+ char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
- if (!br_addif(br_name, vlan_ifname))
- clean |= DVLAN_CLEAN_VLAN_PORT;
-
- dyn_iface_get(hapd, vlan_ifname, clean);
-
- ifconfig_up(vlan_ifname);
- }
-
- if (!br_addif(br_name, ifname))
- vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
-
- ifconfig_up(ifname);
-
- break;
- }
- vlan = vlan->next;
+ if (hapd->conf->vlan_bridge[0]) {
+ os_snprintf(br_name, IFNAMSIZ, "%s%d",
+ hapd->conf->vlan_bridge, vid);
+ } else if (tagged_interface) {
+ os_snprintf(br_name, IFNAMSIZ, "br%s.%d",
+ tagged_interface, vid);
+ } else {
+ os_snprintf(br_name, IFNAMSIZ, "brvlan%d", vid);
}
}
-static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
+static void vlan_get_bridge(const char *br_name, struct hostapd_data *hapd,
+ int vid)
{
- char vlan_ifname[IFNAMSIZ];
- char br_name[IFNAMSIZ];
- struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
int vlan_naming = hapd->conf->ssid.vlan_naming;
+
+ dyn_iface_get(hapd, br_name, br_addbr(br_name) ? 0 : DVLAN_CLEAN_BR);
+
+ ifconfig_up(br_name);
+
+ if (tagged_interface)
+ vlan_newlink_tagged(vlan_naming, tagged_interface, br_name,
+ vid, hapd);
+}
+
+
+static void vlan_newlink(const char *ifname, struct hostapd_data *hapd)
+{
+ char br_name[IFNAMSIZ];
+ struct hostapd_vlan *vlan;
+ int untagged, *tagged, i, notempty;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
+
+ for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+ if (vlan->configured ||
+ os_strcmp(ifname, vlan->ifname) != 0)
+ continue;
+ break;
+ }
+ if (!vlan)
+ return;
+
+ vlan->configured = 1;
+
+ notempty = vlan->vlan_desc.notempty;
+ untagged = vlan->vlan_desc.untagged;
+ tagged = vlan->vlan_desc.tagged;
+
+ if (!notempty) {
+ /* Non-VLAN STA */
+ if (hapd->conf->bridge[0] &&
+ !br_addif(hapd->conf->bridge, ifname))
+ vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
+ } else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
+ vlan_bridge_name(br_name, hapd, untagged);
+
+ vlan_get_bridge(br_name, hapd, untagged);
+
+ if (!br_addif(br_name, ifname))
+ vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
+ }
+
+ for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
+ if (tagged[i] == untagged ||
+ tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
+ (i > 0 && tagged[i] == tagged[i - 1]))
+ continue;
+ vlan_bridge_name(br_name, hapd, tagged[i]);
+ vlan_get_bridge(br_name, hapd, tagged[i]);
+ vlan_newlink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
+ ifname, br_name, tagged[i], hapd);
+ }
+
+ ifconfig_up(ifname);
+}
+
+
+static void vlan_dellink_tagged(int vlan_naming, const char *tagged_interface,
+ const char *br_name, int vid,
+ struct hostapd_data *hapd)
+{
+ char vlan_ifname[IFNAMSIZ];
int clean;
+ if (vlan_naming == DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+ os_snprintf(vlan_ifname, sizeof(vlan_ifname), "%s.%d",
+ tagged_interface, vid);
+ else
+ os_snprintf(vlan_ifname, sizeof(vlan_ifname), "vlan%d", vid);
+
+ clean = dyn_iface_put(hapd, vlan_ifname);
+
+ if (clean & DVLAN_CLEAN_VLAN_PORT)
+ br_delif(br_name, vlan_ifname);
+
+ if (clean & DVLAN_CLEAN_VLAN) {
+ ifconfig_down(vlan_ifname);
+ vlan_rem(vlan_ifname);
+ }
+}
+
+
+static void vlan_put_bridge(const char *br_name, struct hostapd_data *hapd,
+ int vid)
+{
+ int clean;
+ char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+ int vlan_naming = hapd->conf->ssid.vlan_naming;
+
+ if (tagged_interface)
+ vlan_dellink_tagged(vlan_naming, tagged_interface, br_name,
+ vid, hapd);
+
+ clean = dyn_iface_put(hapd, br_name);
+ if ((clean & DVLAN_CLEAN_BR) && br_getnumports(br_name) == 0) {
+ ifconfig_down(br_name);
+ br_delbr(br_name);
+ }
+}
+
+
+static void vlan_dellink(const char *ifname, struct hostapd_data *hapd)
+{
+ struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
+
wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
first = prev = vlan;
while (vlan) {
- if (os_strcmp(ifname, vlan->ifname) == 0 &&
- vlan->configured) {
- if (hapd->conf->vlan_bridge[0]) {
- os_snprintf(br_name, sizeof(br_name), "%s%d",
- hapd->conf->vlan_bridge,
- vlan->vlan_id);
- } else if (tagged_interface) {
- os_snprintf(br_name, sizeof(br_name),
- "br%s.%d", tagged_interface,
- vlan->vlan_id);
- } else {
- os_snprintf(br_name, sizeof(br_name),
- "brvlan%d", vlan->vlan_id);
- }
+ if (os_strcmp(ifname, vlan->ifname) != 0) {
+ prev = vlan;
+ vlan = vlan->next;
+ continue;
+ }
+ break;
+ }
+ if (!vlan)
+ return;
+
+ if (vlan->configured) {
+ int notempty = vlan->vlan_desc.notempty;
+ int untagged = vlan->vlan_desc.untagged;
+ int *tagged = vlan->vlan_desc.tagged;
+ char br_name[IFNAMSIZ];
+ int i;
+
+ for (i = 0; i < MAX_NUM_TAGGED_VLAN && tagged[i]; i++) {
+ if (tagged[i] == untagged ||
+ tagged[i] <= 0 || tagged[i] > MAX_VLAN_ID ||
+ (i > 0 && tagged[i] == tagged[i - 1]))
+ continue;
+ vlan_bridge_name(br_name, hapd, tagged[i]);
+ vlan_dellink_tagged(DYNAMIC_VLAN_NAMING_WITH_DEVICE,
+ ifname, br_name, tagged[i], hapd);
+ vlan_put_bridge(br_name, hapd, tagged[i]);
+ }
+
+ if (!notempty) {
+ /* Non-VLAN STA */
+ if (hapd->conf->bridge[0] &&
+ (vlan->clean & DVLAN_CLEAN_WLAN_PORT))
+ br_delif(hapd->conf->bridge, ifname);
+ } else if (untagged > 0 && untagged <= MAX_VLAN_ID) {
+ vlan_bridge_name(br_name, hapd, untagged);
if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
br_delif(br_name, vlan->ifname);
- if (tagged_interface) {
- if (vlan_naming ==
- DYNAMIC_VLAN_NAMING_WITH_DEVICE)
- os_snprintf(vlan_ifname,
- sizeof(vlan_ifname),
- "%s.%d", tagged_interface,
- vlan->vlan_id);
- else
- os_snprintf(vlan_ifname,
- sizeof(vlan_ifname),
- "vlan%d", vlan->vlan_id);
-
- clean = dyn_iface_put(hapd, vlan_ifname);
-
- if (clean & DVLAN_CLEAN_VLAN_PORT)
- br_delif(br_name, vlan_ifname);
-
- if (clean & DVLAN_CLEAN_VLAN) {
- ifconfig_down(vlan_ifname);
- vlan_rem(vlan_ifname);
- }
- }
-
- clean = dyn_iface_put(hapd, br_name);
- if ((clean & DVLAN_CLEAN_BR) &&
- br_getnumports(br_name) == 0) {
- ifconfig_down(br_name);
- br_delbr(br_name);
- }
+ vlan_put_bridge(br_name, hapd, untagged);
}
-
- if (os_strcmp(ifname, vlan->ifname) == 0) {
- if (vlan == first) {
- hapd->conf->vlan = vlan->next;
- } else {
- prev->next = vlan->next;
- }
- os_free(vlan);
-
- break;
- }
- prev = vlan;
- vlan = vlan->next;
}
+
+ /*
+ * Ensure this VLAN interface is actually removed even if
+ * NEWLINK message is only received later.
+ */
+ if (if_nametoindex(vlan->ifname) && vlan_if_remove(hapd, vlan))
+ wpa_printf(MSG_ERROR,
+ "VLAN: Could not remove VLAN iface: %s: %s",
+ vlan->ifname, strerror(errno));
+
+ if (vlan == first)
+ hapd->conf->vlan = vlan->next;
+ else
+ prev->next = vlan->next;
+
+ os_free(vlan);
}
@@ -977,15 +1053,17 @@
while (vlan) {
next = vlan->next;
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+ /* vlan_dellink() takes care of cleanup and interface removal */
+ if (vlan->vlan_id != VLAN_ID_WILDCARD)
+ vlan_dellink(vlan->ifname, hapd);
+#else /* CONFIG_FULL_DYNAMIC_VLAN */
if (vlan->vlan_id != VLAN_ID_WILDCARD &&
vlan_if_remove(hapd, vlan)) {
wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
"iface: %s: %s",
vlan->ifname, strerror(errno));
}
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
- if (vlan->clean)
- vlan_dellink(vlan->ifname, hapd);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
vlan = next;
@@ -999,7 +1077,8 @@
hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
- if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED &&
+ if ((hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED ||
+ hapd->conf->ssid.per_sta_vif) &&
!hapd->conf->vlan) {
/* dynamic vlans enabled but no (or empty) vlan_file given */
struct hostapd_vlan *vlan;
@@ -1037,13 +1116,13 @@
struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
struct hostapd_vlan *vlan,
- int vlan_id)
+ int vlan_id,
+ struct vlan_description *vlan_desc)
{
struct hostapd_vlan *n = NULL;
char *ifname, *pos;
- if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
- vlan->vlan_id != VLAN_ID_WILDCARD)
+ if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD)
return NULL;
wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
@@ -1061,6 +1140,8 @@
goto free_ifname;
n->vlan_id = vlan_id;
+ if (vlan_desc)
+ n->vlan_desc = *vlan_desc;
n->dynamic_vlan = 1;
os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
@@ -1087,7 +1168,7 @@
{
struct hostapd_vlan *vlan;
- if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
+ if (vlan_id <= 0)
return 1;
wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",