Cumulative patch from commit f89c32e63f71e66d7b55e284016762b603ae02db
f89c32e Android: Fix max number of sched scan SSIDs based on driver capability
f1a5a34 binder: Implement interface add/remove methods
7b4bbb9 binder: Add binder skeletal code for Android
5914ebf Remove struct ieee80211_mgmt::u.probe_req
094e949 atheros: Do not use struct ieee80211_mgmt::u.probe_req
c01120a wpa_supplicant: Do not use struct ieee80211_mgmt::u.probe_req
e1b9962 AP: Do not use struct ieee80211_mgmt::u.probe_req
5cd317d Do not clear PMKSA entry or EAP session cache if config does not change
f933216 Revert "Assign QCA vendor command and attribute for Tx/Rx aggregation"
bde9a4e Comment out UDP/UNIX socket code from common ctrl_iface based on build
a6fbff2 Fix CONFIG_CTRL_IFACE=udp6/udp6-remote builds
0741c48 SAE: Check SHA256-PRF operation result
ea86a34 SAE: Remove dead code in FFC pwd-value derivation
87faf1f nl80211: Fix libnl-tiny build with CONFIG_LIBNL20=y
31afdd2 Use TIOCOUTQ instead of SIOCOUTQ to avoid need for linux/sockios.h
6d07e76 wlantest: Use local ETH_P_IP define instead of linux/if_ether.h
795abc8 Drop USE_KERNEL_HEADERS define
9b7cd57 Use a separate header file for Linux bridge interface definitions
c815fab Use own header file for defining Linux VLAN kernel interface
81606ab vlan: Fix musl libc conflict with Linux kernel headers
f347429 P2P: Fix persistent group for 60 GHz networks
e868599 vlan: Move if_nametoindex() use out of vlan_init.c
7c03c08 vlan: Move ifconfig helpers to a separate file
59d6390 vlan: Move CONFIG_FULL_DYNAMIC_VLAN functionality into a separate file
0fe28dd vlan: Remove unnecessary header includes from netlink implementation
84d6755 vlan: Clean up netlink vs. ioctl API implementation
cb38bc8 vlan: Fix musl build error
954e10e Make it a bit easier to roam from 2.4 GHz to 5 GHz within ESS
585141b Fix a typo in a comment
1126c07 nl80211: Ignore deauth/disassoc event during Connect reassociation
6a5ee81 Include previous BSSID in connection request to indicate reassociation
00c3c4a nl80211: Add NL80211_ATTR_PREV_BSSID with Connect command
cbc3d6f WNM: Verify BSS TM target match against the current network profile
8854f90 mesh: Simplify wpa_auth_pmksa_set_to_sm()
32d4fe9 privsep: Fix a compiler warning on unsigned/signed comparison
2e997ee Add interface matching support with -M, guarded by CONFIG_MATCH_IFACE
45e3fc7 Find correct driver for interface additions/removals
9037702 wpa_supplicant: Fix CONFIG_IBSS_RSN=y build without CONFIG_AP=y
5ae65de wpa_supplicant: Fix p2p_group_add when UDP-based ctrl_iface is used
24bce46 FST: Fix a compiler warning
e567c58 Fix nfc_pw_token build with CONFIG_FST=y
d774c46 mesh: Use appropriate BLOCKED state duration
9f2cf23 mesh: Add support for PMKSA caching
4c522c7 PMKSA: Flush AP/mesh PMKSA cache by PMKSA_FLUSH command
b8daac1 PMKSA: Show AP/mesh PMKSA list in PMKSA command
2604edb mesh: Add MESH_PEER_ADD command
e174ef3 mesh: Add MESH_PEER_REMOVE command
f7648c8 P2P: Advertise IP Address Allocation only if it is enabled on GO
7f46ad9 BSD: Only down the interface once we are sure we can work with it
192964d Handle OSEN IE in Assoc Request info if req_ies exists
29eddc3 nl80211: Fix error path in if_indices_reason reallocation
ee298f1 nl80211: Do not add NL80211_ATTR_SMPS_MODE attribute if HT is disabled
4ca16b5 Assign QCA vendor command and attribute for Tx/Rx aggregation
64ce590 libxml2: Check for xmlDocDumpFormatMemory() error case
8b827c3 BoringSSL: Keep static analyzers happier with X509_get0_pubkey_bitstr()
42a9553 hs20-osu-client: Fix pol_upd command line parsing
ec1eae8 hs20-osu-client: Remove dead code from sub_rem command line parsing
c3dc68e Do not invalidate EAP session cache on all network block parameter changes
9231c24 wlantest: Fix bip_protect() memory allocation
c6c29be Interworking: Add credential realm to EAP-TLS identity
Change-Id: I870f325171d00fed9c4fcd82a695fe5e2efee792
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 0720e14..19bff7b 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -685,12 +685,12 @@
u16 csa_offs[2];
size_t csa_offs_len;
- ie = mgmt->u.probe_req.variable;
- if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+ if (len < IEEE80211_HDRLEN)
return;
+ ie = ((const u8 *) mgmt) + IEEE80211_HDRLEN;
if (hapd->iconf->track_sta_max_num)
sta_track_add(hapd->iface, mgmt->sa);
- ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+ ie_len = len - IEEE80211_HDRLEN;
for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 9f249d7..317b238 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -568,3 +568,16 @@
{
return hostapd_drv_stop_ap(hapd);
}
+
+
+int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
+ size_t len)
+{
+ return wpa_auth_pmksa_list(hapd->wpa_auth, buf, len);
+}
+
+
+void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd)
+{
+ wpa_auth_pmksa_flush(hapd->wpa_auth);
+}
diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h
index e5297d0..3ad622f 100644
--- a/src/ap/ctrl_iface_ap.h
+++ b/src/ap/ctrl_iface_ap.h
@@ -24,5 +24,8 @@
int hostapd_parse_csa_settings(const char *pos,
struct csa_settings *settings);
int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd);
+int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf,
+ size_t len);
+void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd);
#endif /* CTRL_IFACE_AP_H */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index f54d1ad..3ab5bf3 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -1353,4 +1353,31 @@
}
}
+
+void wpa_supplicant_event_global(void *ctx, enum wpa_event_type event,
+ union wpa_event_data *data)
+{
+ struct hapd_interfaces *interfaces = ctx;
+ struct hostapd_data *hapd;
+
+ if (event != EVENT_INTERFACE_STATUS)
+ return;
+
+ hapd = hostapd_get_iface(interfaces, data->interface_status.ifname);
+ if (hapd && hapd->driver && hapd->driver->get_ifindex &&
+ hapd->drv_priv) {
+ unsigned int ifindex;
+
+ ifindex = hapd->driver->get_ifindex(hapd->drv_priv);
+ if (ifindex != data->interface_status.ifindex) {
+ wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+ "interface status ifindex %d mismatch (%d)",
+ ifindex, data->interface_status.ifindex);
+ return;
+ }
+ }
+ if (hapd)
+ wpa_supplicant_event(hapd, event, data);
+}
+
#endif /* HOSTAPD */
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 55ca9e8..ee80f4f 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -3090,6 +3090,8 @@
hostapd_enable_iface(iface);
}
+#endif /* NEED_AP_MLME */
+
struct hostapd_data * hostapd_get_iface(struct hapd_interfaces *interfaces,
const char *ifname)
@@ -3110,8 +3112,6 @@
return NULL;
}
-#endif /* NEED_AP_MLME */
-
void hostapd_periodic_iface(struct hostapd_iface *iface)
{
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 60516ae..75a7c04 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -262,6 +262,7 @@
struct sta_info *sta);
struct wpabuf *mesh_pending_auth;
struct os_reltime mesh_pending_auth_time;
+ u8 mesh_required_peer[ETH_ALEN];
#endif /* CONFIG_MESH */
#ifdef CONFIG_SQLITE
diff --git a/src/ap/iapp.c b/src/ap/iapp.c
index 99aa04d..07672ce 100644
--- a/src/ap/iapp.c
+++ b/src/ap/iapp.c
@@ -34,11 +34,7 @@
#include "utils/includes.h"
#include <net/if.h>
#include <sys/ioctl.h>
-#ifdef USE_KERNEL_HEADERS
-#include <linux/if_packet.h>
-#else /* USE_KERNEL_HEADERS */
#include <netpacket/packet.h>
-#endif /* USE_KERNEL_HEADERS */
#include "utils/common.h"
#include "utils/eloop.h"
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 134ae06..6a373c5 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -554,6 +554,18 @@
}
+void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ sta->flags |= WLAN_STA_AUTH;
+ sta->auth_alg = WLAN_AUTH_SAE;
+ mlme_authenticate_indication(hapd, sta);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+ sta->sae->state = SAE_ACCEPTED;
+ wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
+ sta->sae->pmk, sta->sae->pmkid);
+}
+
+
static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *bssid, u8 auth_transaction)
{
@@ -676,13 +688,7 @@
sae_set_retransmit_timer(hapd, sta);
} else {
- sta->flags |= WLAN_STA_AUTH;
- sta->auth_alg = WLAN_AUTH_SAE;
- mlme_authenticate_indication(hapd, sta);
- wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
- sta->sae->state = SAE_ACCEPTED;
- wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
- sta->sae->pmk, sta->sae->pmkid);
+ sae_accept_sta(hapd, sta);
}
break;
case SAE_ACCEPTED:
@@ -691,6 +697,7 @@
") doing reauthentication",
MAC2STR(sta->addr));
ap_free_sta(hapd, sta);
+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
} else {
if (sae_check_big_sync(sta))
return WLAN_STATUS_SUCCESS;
@@ -733,6 +740,13 @@
sta->sae->sync = 0;
}
+ if (sta->mesh_sae_pmksa_caching) {
+ wpa_printf(MSG_DEBUG,
+ "SAE: Cancel use of mesh PMKSA caching because peer starts SAE authentication");
+ wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+ sta->mesh_sae_pmksa_caching = 0;
+ }
+
if (auth_transaction == 1) {
const u8 *token = NULL, *pos, *end;
size_t token_len = 0;
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 1a96b33..71b3b49 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -102,6 +102,7 @@
#ifdef CONFIG_SAE
void sae_clear_retransmit_timer(struct hostapd_data *hapd,
struct sta_info *sta);
+void sae_accept_sta(struct hostapd_data *hapd, struct sta_info *sta);
#else /* CONFIG_SAE */
static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
struct sta_info *sta)
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 30be30c..d610e7e 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -92,6 +92,20 @@
}
+/**
+ * pmksa_cache_auth_flush - Flush all PMKSA cache entries
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ */
+void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa)
+{
+ while (pmksa->pmksa) {
+ wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry for "
+ MACSTR, MAC2STR(pmksa->pmksa->spa));
+ pmksa_cache_free_entry(pmksa, pmksa->pmksa);
+ }
+}
+
+
static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
{
struct rsn_pmksa_cache *pmksa = eloop_ctx;
@@ -167,8 +181,6 @@
struct rsn_pmksa_cache_entry *entry,
struct eapol_state_machine *eapol)
{
- struct sta_info *sta;
-
if (entry == NULL || eapol == NULL)
return;
@@ -199,8 +211,9 @@
}
eapol->eap_type_authsrv = entry->eap_type_authsrv;
- sta = (struct sta_info *) eapol->sta;
- ap_sta_set_vlan(hapd, sta, entry->vlan_desc);
+#ifndef CONFIG_NO_VLAN
+ ap_sta_set_vlan(hapd, eapol->sta, entry->vlan_desc);
+#endif /* CONFIG_NO_VLAN */
eapol->acct_multi_session_id = entry->acct_multi_session_id;
}
@@ -547,3 +560,48 @@
return found ? 0 : -1;
}
+
+
+/**
+ * pmksa_cache_auth_list - Dump text list of entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ * @buf: Buffer for the list
+ * @len: Length of the buffer
+ * Returns: Number of bytes written to buffer
+ *
+ * This function is used to generate a text format representation of the
+ * current PMKSA cache contents for the ctrl_iface PMKSA command.
+ */
+int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
+{
+ int i, ret;
+ char *pos = buf;
+ struct rsn_pmksa_cache_entry *entry;
+ struct os_reltime now;
+
+ os_get_reltime(&now);
+ ret = os_snprintf(pos, buf + len - pos,
+ "Index / SPA / PMKID / expiration (in seconds) / opportunistic\n");
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+ i = 0;
+ entry = pmksa->pmksa;
+ while (entry) {
+ ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
+ i, MAC2STR(entry->spa));
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
+ PMKID_LEN);
+ ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
+ (int) (entry->expiration - now.sec),
+ entry->opportunistic);
+ if (os_snprintf_error(buf + len - pos, ret))
+ return pos - buf;
+ pos += ret;
+ entry = entry->next;
+ }
+ return pos - buf;
+}
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index 3e60277..d8d9c5a 100644
--- a/src/ap/pmksa_cache_auth.h
+++ b/src/ap/pmksa_cache_auth.h
@@ -63,5 +63,7 @@
struct rsn_pmksa_cache_entry *entry);
int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
struct radius_das_attrs *attr);
+int pmksa_cache_auth_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
+void pmksa_cache_auth_flush(struct rsn_pmksa_cache *pmksa);
#endif /* PMKSA_CACHE_H */
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 70a59cc..3d9a928 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -183,6 +183,7 @@
#ifdef CONFIG_SAE
struct sae_data *sae;
+ unsigned int mesh_sae_pmksa_caching:1;
#endif /* CONFIG_SAE */
u32 session_timeout; /* valid only if session_timeout_set == 1 */
diff --git a/src/ap/vlan_full.c b/src/ap/vlan_full.c
new file mode 100644
index 0000000..aa42335
--- /dev/null
+++ b/src/ap/vlan_full.c
@@ -0,0 +1,752 @@
+/*
+ * hostapd / VLAN initialization - full dynamic VLAN
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <net/if.h>
+/* Avoid conflicts due to NetBSD net/if.h if_type define with driver.h */
+#undef if_type
+#include <sys/ioctl.h>
+
+#include "utils/common.h"
+#include "drivers/priv_netlink.h"
+#include "common/linux_bridge.h"
+#include "common/linux_vlan.h"
+#include "utils/eloop.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "wpa_auth.h"
+#include "vlan_init.h"
+#include "vlan_util.h"
+
+
+struct full_dynamic_vlan {
+ int s; /* socket on which to listen for new/removed interfaces. */
+};
+
+#define DVLAN_CLEAN_BR 0x1
+#define DVLAN_CLEAN_VLAN 0x2
+#define DVLAN_CLEAN_VLAN_PORT 0x4
+
+struct dynamic_iface {
+ char ifname[IFNAMSIZ + 1];
+ int usage;
+ int clean;
+ struct dynamic_iface *next;
+};
+
+
+/* Increment ref counter for ifname and add clean flag.
+ * If not in list, add it only if some flags are given.
+ */
+static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
+ int clean)
+{
+ struct dynamic_iface *next, **dynamic_ifaces;
+ struct hapd_interfaces *interfaces;
+
+ interfaces = hapd->iface->interfaces;
+ dynamic_ifaces = &interfaces->vlan_priv;
+
+ for (next = *dynamic_ifaces; next; next = next->next) {
+ if (os_strcmp(ifname, next->ifname) == 0)
+ break;
+ }
+
+ if (next) {
+ next->usage++;
+ next->clean |= clean;
+ return;
+ }
+
+ if (!clean)
+ return;
+
+ next = os_zalloc(sizeof(*next));
+ if (!next)
+ return;
+ os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
+ next->usage = 1;
+ next->clean = clean;
+ next->next = *dynamic_ifaces;
+ *dynamic_ifaces = next;
+}
+
+
+/* Decrement reference counter for given ifname.
+ * Return clean flag iff reference counter was decreased to zero, else zero
+ */
+static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
+{
+ struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
+ struct hapd_interfaces *interfaces;
+ int clean;
+
+ interfaces = hapd->iface->interfaces;
+ dynamic_ifaces = &interfaces->vlan_priv;
+
+ for (next = *dynamic_ifaces; next; next = next->next) {
+ if (os_strcmp(ifname, next->ifname) == 0)
+ break;
+ prev = next;
+ }
+
+ if (!next)
+ return 0;
+
+ next->usage--;
+ if (next->usage)
+ return 0;
+
+ if (prev)
+ prev->next = next->next;
+ else
+ *dynamic_ifaces = next->next;
+ clean = next->clean;
+ os_free(next);
+
+ return clean;
+}
+
+
+static int ifconfig_down(const char *if_name)
+{
+ wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
+ return ifconfig_helper(if_name, 0);
+}
+
+
+/* This value should be 256 ONLY. If it is something else, then hostapd
+ * might crash!, as this value has been hard-coded in 2.4.x kernel
+ * bridging code.
+ */
+#define MAX_BR_PORTS 256
+
+static int br_delif(const char *br_name, const char *if_name)
+{
+ int fd;
+ struct ifreq ifr;
+ unsigned long args[2];
+ int if_index;
+
+ wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ if_index = if_nametoindex(if_name);
+
+ if (if_index == 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
+ "interface index for '%s'",
+ __func__, if_name);
+ close(fd);
+ return -1;
+ }
+
+ args[0] = BRCTL_DEL_IF;
+ args[1] = if_index;
+
+ os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (void *) args;
+
+ if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
+ /* No error if interface already removed. */
+ wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
+ "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
+ "%s", __func__, br_name, if_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+/*
+ Add interface 'if_name' to the bridge 'br_name'
+
+ returns -1 on error
+ returns 1 if the interface is already part of the bridge
+ returns 0 otherwise
+*/
+static int br_addif(const char *br_name, const char *if_name)
+{
+ int fd;
+ struct ifreq ifr;
+ unsigned long args[2];
+ int if_index;
+
+ wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ if_index = if_nametoindex(if_name);
+
+ if (if_index == 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
+ "interface index for '%s'",
+ __func__, if_name);
+ close(fd);
+ return -1;
+ }
+
+ args[0] = BRCTL_ADD_IF;
+ args[1] = if_index;
+
+ os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (void *) args;
+
+ if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
+ if (errno == EBUSY) {
+ /* The interface is already added. */
+ close(fd);
+ return 1;
+ }
+
+ wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
+ "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
+ "%s", __func__, br_name, if_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+static int br_delbr(const char *br_name)
+{
+ int fd;
+ unsigned long arg[2];
+
+ wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ arg[0] = BRCTL_DEL_BRIDGE;
+ arg[1] = (unsigned long) br_name;
+
+ if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
+ /* No error if bridge already removed. */
+ wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
+ "%s: %s", __func__, br_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+/*
+ Add a bridge with the name 'br_name'.
+
+ returns -1 on error
+ returns 1 if the bridge already exists
+ returns 0 otherwise
+*/
+static int br_addbr(const char *br_name)
+{
+ int fd;
+ unsigned long arg[4];
+ struct ifreq ifr;
+
+ wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ arg[0] = BRCTL_ADD_BRIDGE;
+ arg[1] = (unsigned long) br_name;
+
+ if (ioctl(fd, SIOCGIFBR, arg) < 0) {
+ if (errno == EEXIST) {
+ /* The bridge is already added. */
+ close(fd);
+ return 1;
+ } else {
+ wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
+ "failed for %s: %s",
+ __func__, br_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+ }
+
+ /* Decrease forwarding delay to avoid EAPOL timeouts. */
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
+ arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
+ arg[1] = 1;
+ arg[2] = 0;
+ arg[3] = 0;
+ ifr.ifr_data = (char *) &arg;
+ if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: "
+ "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
+ "%s: %s", __func__, br_name, strerror(errno));
+ /* Continue anyway */
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+static int br_getnumports(const char *br_name)
+{
+ int fd;
+ int i;
+ int port_cnt = 0;
+ unsigned long arg[4];
+ int ifindices[MAX_BR_PORTS];
+ struct ifreq ifr;
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ arg[0] = BRCTL_GET_PORT_LIST;
+ arg[1] = (unsigned long) ifindices;
+ arg[2] = MAX_BR_PORTS;
+ arg[3] = 0;
+
+ os_memset(ifindices, 0, sizeof(ifindices));
+ os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+ ifr.ifr_data = (void *) arg;
+
+ if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
+ "failed for %s: %s",
+ __func__, br_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ for (i = 1; i < MAX_BR_PORTS; i++) {
+ if (ifindices[i] > 0) {
+ port_cnt++;
+ }
+ }
+
+ close(fd);
+ return port_cnt;
+}
+
+
+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];
+ 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 = 0;
+ ifconfig_up(tagged_interface);
+ if (!vlan_add(tagged_interface, vid, vlan_ifname))
+ clean |= DVLAN_CLEAN_VLAN;
+
+ if (!br_addif(br_name, vlan_ifname))
+ clean |= DVLAN_CLEAN_VLAN_PORT;
+
+ dyn_iface_get(hapd, vlan_ifname, clean);
+
+ ifconfig_up(vlan_ifname);
+}
+
+
+static void vlan_bridge_name(char *br_name, struct hostapd_data *hapd, int vid)
+{
+ char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+
+ 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_get_bridge(const char *br_name, struct hostapd_data *hapd,
+ int vid)
+{
+ 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);
+}
+
+
+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);
+ }
+}
+
+
+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) {
+ 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);
+
+ vlan_put_bridge(br_name, hapd, untagged);
+ }
+ }
+
+ /*
+ * 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);
+}
+
+
+static void
+vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
+ struct hostapd_data *hapd)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, nlmsg_len, rta_len;
+ struct rtattr *attr;
+ char ifname[IFNAMSIZ + 1];
+
+ if (len < sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+ os_memset(ifname, 0, sizeof(ifname));
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ int n = attr->rta_len - rta_len;
+ if (n < 0)
+ break;
+
+ if ((size_t) n >= sizeof(ifname))
+ n = sizeof(ifname) - 1;
+ os_memcpy(ifname, ((char *) attr) + rta_len, n);
+
+ }
+
+ attr = RTA_NEXT(attr, attrlen);
+ }
+
+ if (!ifname[0])
+ return;
+ if (del && if_nametoindex(ifname)) {
+ /* interface still exists, race condition ->
+ * iface has just been recreated */
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
+ del ? "DEL" : "NEW",
+ ifi->ifi_index, ifname, ifi->ifi_family, ifi->ifi_flags,
+ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+
+ if (del)
+ vlan_dellink(ifname, hapd);
+ else
+ vlan_newlink(ifname, hapd);
+}
+
+
+static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ char buf[8192];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+ struct hostapd_data *hapd = eloop_ctx;
+
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
+ __func__, strerror(errno));
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (NLMSG_OK(h, left)) {
+ int len, plen;
+
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
+ "message: len=%d left=%d plen=%d",
+ len, left, plen);
+ break;
+ }
+
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ vlan_read_ifnames(h, plen, 0, hapd);
+ break;
+ case RTM_DELLINK:
+ vlan_read_ifnames(h, plen, 1, hapd);
+ break;
+ }
+
+ h = NLMSG_NEXT(h, left);
+ }
+
+ if (left > 0) {
+ wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
+ "netlink message", __func__, left);
+ }
+}
+
+
+struct full_dynamic_vlan *
+full_dynamic_vlan_init(struct hostapd_data *hapd)
+{
+ struct sockaddr_nl local;
+ struct full_dynamic_vlan *priv;
+
+ priv = os_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ return NULL;
+
+ vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
+ DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
+ VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
+ VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
+
+ priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (priv->s < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
+ "NETLINK_ROUTE) failed: %s",
+ __func__, strerror(errno));
+ os_free(priv);
+ return NULL;
+ }
+
+ os_memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+ if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
+ __func__, strerror(errno));
+ close(priv->s);
+ os_free(priv);
+ return NULL;
+ }
+
+ if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
+ {
+ close(priv->s);
+ os_free(priv);
+ return NULL;
+ }
+
+ return priv;
+}
+
+
+void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
+{
+ if (priv == NULL)
+ return;
+ eloop_unregister_read_sock(priv->s);
+ close(priv->s);
+ os_free(priv);
+}
diff --git a/src/ap/vlan_ifconfig.c b/src/ap/vlan_ifconfig.c
new file mode 100644
index 0000000..ef953a5
--- /dev/null
+++ b/src/ap/vlan_ifconfig.c
@@ -0,0 +1,69 @@
+/*
+ * hostapd / VLAN ifconfig helpers
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include "utils/common.h"
+#include "vlan_util.h"
+
+
+int ifconfig_helper(const char *if_name, int up)
+{
+ int fd;
+ struct ifreq ifr;
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
+
+ if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
+ "for interface %s: %s",
+ __func__, if_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ if (up)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
+ "for interface %s (up=%d): %s",
+ __func__, if_name, up, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+int ifconfig_up(const char *if_name)
+{
+ wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
+ return ifconfig_helper(if_name, 1);
+}
+
+
+int iface_exists(const char *ifname)
+{
+ return if_nametoindex(ifname);
+}
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 45d1a1c..31e4fc6 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -18,158 +18,6 @@
#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
-
-#include "drivers/priv_netlink.h"
-#include "utils/eloop.h"
-
-
-struct full_dynamic_vlan {
- int s; /* socket on which to listen for new/removed interfaces. */
-};
-
-#define DVLAN_CLEAN_BR 0x1
-#define DVLAN_CLEAN_VLAN 0x2
-#define DVLAN_CLEAN_VLAN_PORT 0x4
-
-struct dynamic_iface {
- char ifname[IFNAMSIZ + 1];
- int usage;
- int clean;
- struct dynamic_iface *next;
-};
-
-
-/* Increment ref counter for ifname and add clean flag.
- * If not in list, add it only if some flags are given.
- */
-static void dyn_iface_get(struct hostapd_data *hapd, const char *ifname,
- int clean)
-{
- struct dynamic_iface *next, **dynamic_ifaces;
- struct hapd_interfaces *interfaces;
-
- interfaces = hapd->iface->interfaces;
- dynamic_ifaces = &interfaces->vlan_priv;
-
- for (next = *dynamic_ifaces; next; next = next->next) {
- if (os_strcmp(ifname, next->ifname) == 0)
- break;
- }
-
- if (next) {
- next->usage++;
- next->clean |= clean;
- return;
- }
-
- if (!clean)
- return;
-
- next = os_zalloc(sizeof(*next));
- if (!next)
- return;
- os_strlcpy(next->ifname, ifname, sizeof(next->ifname));
- next->usage = 1;
- next->clean = clean;
- next->next = *dynamic_ifaces;
- *dynamic_ifaces = next;
-}
-
-
-/* Decrement reference counter for given ifname.
- * Return clean flag iff reference counter was decreased to zero, else zero
- */
-static int dyn_iface_put(struct hostapd_data *hapd, const char *ifname)
-{
- struct dynamic_iface *next, *prev = NULL, **dynamic_ifaces;
- struct hapd_interfaces *interfaces;
- int clean;
-
- interfaces = hapd->iface->interfaces;
- dynamic_ifaces = &interfaces->vlan_priv;
-
- for (next = *dynamic_ifaces; next; next = next->next) {
- if (os_strcmp(ifname, next->ifname) == 0)
- break;
- prev = next;
- }
-
- if (!next)
- return 0;
-
- next->usage--;
- if (next->usage)
- return 0;
-
- if (prev)
- prev->next = next->next;
- else
- *dynamic_ifaces = next->next;
- clean = next->clean;
- os_free(next);
-
- return clean;
-}
-
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-
-
-static int ifconfig_helper(const char *if_name, int up)
-{
- int fd;
- struct ifreq ifr;
-
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
-
- if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
- "for interface %s: %s",
- __func__, if_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- if (up)
- ifr.ifr_flags |= IFF_UP;
- else
- ifr.ifr_flags &= ~IFF_UP;
-
- if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
- "for interface %s (up=%d): %s",
- __func__, if_name, up, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-static int ifconfig_up(const char *if_name)
-{
- wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
- return ifconfig_helper(if_name, 1);
-}
-
static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
int existsok)
@@ -185,7 +33,7 @@
return -1;
}
- if (!if_nametoindex(vlan->ifname))
+ if (!iface_exists(vlan->ifname))
ret = hostapd_vlan_if_add(hapd, vlan->ifname);
else if (!existsok)
return -1;
@@ -216,7 +64,7 @@
}
-static int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
+int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
{
int ret;
@@ -230,798 +78,6 @@
}
-#ifdef CONFIG_FULL_DYNAMIC_VLAN
-
-static int ifconfig_down(const char *if_name)
-{
- wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
- return ifconfig_helper(if_name, 0);
-}
-
-
-/*
- * These are only available in recent linux headers (without the leading
- * underscore).
- */
-#define _GET_VLAN_REALDEV_NAME_CMD 8
-#define _GET_VLAN_VID_CMD 9
-
-/* This value should be 256 ONLY. If it is something else, then hostapd
- * might crash!, as this value has been hard-coded in 2.4.x kernel
- * bridging code.
- */
-#define MAX_BR_PORTS 256
-
-static int br_delif(const char *br_name, const char *if_name)
-{
- int fd;
- struct ifreq ifr;
- unsigned long args[2];
- int if_index;
-
- wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- if_index = if_nametoindex(if_name);
-
- if (if_index == 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
- "interface index for '%s'",
- __func__, if_name);
- close(fd);
- return -1;
- }
-
- args[0] = BRCTL_DEL_IF;
- args[1] = if_index;
-
- os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
- ifr.ifr_data = (__caddr_t) args;
-
- if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
- /* No error if interface already removed. */
- wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
- "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
- "%s", __func__, br_name, if_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-/*
- Add interface 'if_name' to the bridge 'br_name'
-
- returns -1 on error
- returns 1 if the interface is already part of the bridge
- returns 0 otherwise
-*/
-static int br_addif(const char *br_name, const char *if_name)
-{
- int fd;
- struct ifreq ifr;
- unsigned long args[2];
- int if_index;
-
- wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- if_index = if_nametoindex(if_name);
-
- if (if_index == 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
- "interface index for '%s'",
- __func__, if_name);
- close(fd);
- return -1;
- }
-
- args[0] = BRCTL_ADD_IF;
- args[1] = if_index;
-
- os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
- ifr.ifr_data = (__caddr_t) args;
-
- if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
- if (errno == EBUSY) {
- /* The interface is already added. */
- close(fd);
- return 1;
- }
-
- wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
- "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
- "%s", __func__, br_name, if_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-static int br_delbr(const char *br_name)
-{
- int fd;
- unsigned long arg[2];
-
- wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- arg[0] = BRCTL_DEL_BRIDGE;
- arg[1] = (unsigned long) br_name;
-
- if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
- /* No error if bridge already removed. */
- wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
- "%s: %s", __func__, br_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-/*
- Add a bridge with the name 'br_name'.
-
- returns -1 on error
- returns 1 if the bridge already exists
- returns 0 otherwise
-*/
-static int br_addbr(const char *br_name)
-{
- int fd;
- unsigned long arg[4];
- struct ifreq ifr;
-
- wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- arg[0] = BRCTL_ADD_BRIDGE;
- arg[1] = (unsigned long) br_name;
-
- if (ioctl(fd, SIOCGIFBR, arg) < 0) {
- if (errno == EEXIST) {
- /* The bridge is already added. */
- close(fd);
- return 1;
- } else {
- wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
- "failed for %s: %s",
- __func__, br_name, strerror(errno));
- close(fd);
- return -1;
- }
- }
-
- /* Decrease forwarding delay to avoid EAPOL timeouts. */
- os_memset(&ifr, 0, sizeof(ifr));
- os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
- arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
- arg[1] = 1;
- arg[2] = 0;
- arg[3] = 0;
- ifr.ifr_data = (char *) &arg;
- if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: "
- "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
- "%s: %s", __func__, br_name, strerror(errno));
- /* Continue anyway */
- }
-
- close(fd);
- return 0;
-}
-
-
-static int br_getnumports(const char *br_name)
-{
- int fd;
- int i;
- int port_cnt = 0;
- unsigned long arg[4];
- int ifindices[MAX_BR_PORTS];
- struct ifreq ifr;
-
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- arg[0] = BRCTL_GET_PORT_LIST;
- arg[1] = (unsigned long) ifindices;
- arg[2] = MAX_BR_PORTS;
- arg[3] = 0;
-
- os_memset(ifindices, 0, sizeof(ifindices));
- os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
- ifr.ifr_data = (__caddr_t) arg;
-
- if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
- "failed for %s: %s",
- __func__, br_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- for (i = 1; i < MAX_BR_PORTS; i++) {
- if (ifindices[i] > 0) {
- port_cnt++;
- }
- }
-
- close(fd);
- return port_cnt;
-}
-
-
-#ifndef CONFIG_VLAN_NETLINK
-
-int vlan_rem(const char *if_name)
-{
- int fd;
- struct vlan_ioctl_args if_request;
-
- wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
- if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
- wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
- if_name);
- return -1;
- }
-
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- os_memset(&if_request, 0, sizeof(if_request));
-
- os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
- if_request.cmd = DEL_VLAN_CMD;
-
- if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
- "%s", __func__, if_name, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-/*
- Add a vlan interface with VLAN ID 'vid' and tagged interface
- 'if_name'.
-
- returns -1 on error
- returns 1 if the interface already exists
- returns 0 otherwise
-*/
-int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
-{
- int fd;
- struct vlan_ioctl_args if_request;
-
- wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
- if_name, vid);
- ifconfig_up(if_name);
-
- if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
- wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
- if_name);
- return -1;
- }
-
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- os_memset(&if_request, 0, sizeof(if_request));
-
- /* Determine if a suitable vlan device already exists. */
-
- os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
- vid);
-
- if_request.cmd = _GET_VLAN_VID_CMD;
-
- if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
-
- if (if_request.u.VID == vid) {
- if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
-
- if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
- os_strncmp(if_request.u.device2, if_name,
- sizeof(if_request.u.device2)) == 0) {
- close(fd);
- wpa_printf(MSG_DEBUG, "VLAN: vlan_add: "
- "if_name %s exists already",
- if_request.device1);
- return 1;
- }
- }
- }
-
- /* A suitable vlan device does not already exist, add one. */
-
- os_memset(&if_request, 0, sizeof(if_request));
- os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
- if_request.u.VID = vid;
- if_request.cmd = ADD_VLAN_CMD;
-
- if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: "
- "%s",
- __func__, if_request.device1, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-
-static int vlan_set_name_type(unsigned int name_type)
-{
- int fd;
- struct vlan_ioctl_args if_request;
-
- wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
- name_type);
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
- "failed: %s", __func__, strerror(errno));
- return -1;
- }
-
- os_memset(&if_request, 0, sizeof(if_request));
-
- if_request.u.name_type = name_type;
- if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
- if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD "
- "name_type=%u failed: %s",
- __func__, name_type, strerror(errno));
- close(fd);
- return -1;
- }
-
- close(fd);
- return 0;
-}
-
-#endif /* CONFIG_VLAN_NETLINK */
-
-
-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];
- 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 = 0;
- ifconfig_up(tagged_interface);
- if (!vlan_add(tagged_interface, vid, vlan_ifname))
- clean |= DVLAN_CLEAN_VLAN;
-
- if (!br_addif(br_name, vlan_ifname))
- clean |= DVLAN_CLEAN_VLAN_PORT;
-
- dyn_iface_get(hapd, vlan_ifname, clean);
-
- ifconfig_up(vlan_ifname);
-}
-
-
-static void vlan_bridge_name(char *br_name, struct hostapd_data *hapd, int vid)
-{
- char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
-
- 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_get_bridge(const char *br_name, struct hostapd_data *hapd,
- int vid)
-{
- 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) {
- 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);
-
- vlan_put_bridge(br_name, hapd, untagged);
- }
- }
-
- /*
- * 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);
-}
-
-
-static void
-vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
- struct hostapd_data *hapd)
-{
- struct ifinfomsg *ifi;
- int attrlen, nlmsg_len, rta_len;
- struct rtattr *attr;
- char ifname[IFNAMSIZ + 1];
-
- if (len < sizeof(*ifi))
- return;
-
- ifi = NLMSG_DATA(h);
-
- nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
-
- attrlen = h->nlmsg_len - nlmsg_len;
- if (attrlen < 0)
- return;
-
- attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
-
- os_memset(ifname, 0, sizeof(ifname));
- rta_len = RTA_ALIGN(sizeof(struct rtattr));
- while (RTA_OK(attr, attrlen)) {
- if (attr->rta_type == IFLA_IFNAME) {
- int n = attr->rta_len - rta_len;
- if (n < 0)
- break;
-
- if ((size_t) n >= sizeof(ifname))
- n = sizeof(ifname) - 1;
- os_memcpy(ifname, ((char *) attr) + rta_len, n);
-
- }
-
- attr = RTA_NEXT(attr, attrlen);
- }
-
- if (!ifname[0])
- return;
- if (del && if_nametoindex(ifname)) {
- /* interface still exists, race condition ->
- * iface has just been recreated */
- return;
- }
-
- wpa_printf(MSG_DEBUG,
- "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
- del ? "DEL" : "NEW",
- ifi->ifi_index, ifname, ifi->ifi_family, ifi->ifi_flags,
- (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
- (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
- (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
- (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
-
- if (del)
- vlan_dellink(ifname, hapd);
- else
- vlan_newlink(ifname, hapd);
-}
-
-
-static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
-{
- char buf[8192];
- int left;
- struct sockaddr_nl from;
- socklen_t fromlen;
- struct nlmsghdr *h;
- struct hostapd_data *hapd = eloop_ctx;
-
- fromlen = sizeof(from);
- left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
- (struct sockaddr *) &from, &fromlen);
- if (left < 0) {
- if (errno != EINTR && errno != EAGAIN)
- wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
- __func__, strerror(errno));
- return;
- }
-
- h = (struct nlmsghdr *) buf;
- while (NLMSG_OK(h, left)) {
- int len, plen;
-
- len = h->nlmsg_len;
- plen = len - sizeof(*h);
- if (len > left || plen < 0) {
- wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
- "message: len=%d left=%d plen=%d",
- len, left, plen);
- break;
- }
-
- switch (h->nlmsg_type) {
- case RTM_NEWLINK:
- vlan_read_ifnames(h, plen, 0, hapd);
- break;
- case RTM_DELLINK:
- vlan_read_ifnames(h, plen, 1, hapd);
- break;
- }
-
- h = NLMSG_NEXT(h, left);
- }
-
- if (left > 0) {
- wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
- "netlink message", __func__, left);
- }
-}
-
-
-static struct full_dynamic_vlan *
-full_dynamic_vlan_init(struct hostapd_data *hapd)
-{
- struct sockaddr_nl local;
- struct full_dynamic_vlan *priv;
-
- priv = os_zalloc(sizeof(*priv));
- if (priv == NULL)
- return NULL;
-
-#ifndef CONFIG_VLAN_NETLINK
- vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
- DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
- VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
- VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
-#endif /* CONFIG_VLAN_NETLINK */
-
- priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (priv->s < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
- "NETLINK_ROUTE) failed: %s",
- __func__, strerror(errno));
- os_free(priv);
- return NULL;
- }
-
- os_memset(&local, 0, sizeof(local));
- local.nl_family = AF_NETLINK;
- local.nl_groups = RTMGRP_LINK;
- if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
- wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
- __func__, strerror(errno));
- close(priv->s);
- os_free(priv);
- return NULL;
- }
-
- if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
- {
- close(priv->s);
- os_free(priv);
- return NULL;
- }
-
- return priv;
-}
-
-
-static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
-{
- if (priv == NULL)
- return;
- eloop_unregister_read_sock(priv->s);
- close(priv->s);
- os_free(priv);
-}
-#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-
-
static int vlan_dynamic_add(struct hostapd_data *hapd,
struct hostapd_vlan *vlan)
{
diff --git a/src/ap/vlan_ioctl.c b/src/ap/vlan_ioctl.c
new file mode 100644
index 0000000..987b612
--- /dev/null
+++ b/src/ap/vlan_ioctl.c
@@ -0,0 +1,155 @@
+/*
+ * hostapd / VLAN ioctl API
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <sys/ioctl.h>
+
+#include "utils/common.h"
+#include "common/linux_vlan.h"
+#include "vlan_util.h"
+
+
+int vlan_rem(const char *if_name)
+{
+ int fd;
+ struct vlan_ioctl_args if_request;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
+ if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
+ wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+ if_name);
+ return -1;
+ }
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ os_memset(&if_request, 0, sizeof(if_request));
+
+ os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
+ if_request.cmd = DEL_VLAN_CMD;
+
+ if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
+ "%s", __func__, if_name, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+/*
+ Add a vlan interface with VLAN ID 'vid' and tagged interface
+ 'if_name'.
+
+ returns -1 on error
+ returns 1 if the interface already exists
+ returns 0 otherwise
+*/
+int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
+{
+ int fd;
+ struct vlan_ioctl_args if_request;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
+ if_name, vid);
+ ifconfig_up(if_name);
+
+ if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
+ wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+ if_name);
+ return -1;
+ }
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+ "failed: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ os_memset(&if_request, 0, sizeof(if_request));
+
+ /* Determine if a suitable vlan device already exists. */
+
+ os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
+ vid);
+
+ if_request.cmd = GET_VLAN_VID_CMD;
+
+ if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
+ if_request.u.VID == vid) {
+ if_request.cmd = GET_VLAN_REALDEV_NAME_CMD;
+
+ if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
+ os_strncmp(if_request.u.device2, if_name,
+ sizeof(if_request.u.device2)) == 0) {
+ close(fd);
+ wpa_printf(MSG_DEBUG,
+ "VLAN: vlan_add: if_name %s exists already",
+ if_request.device1);
+ return 1;
+ }
+ }
+
+ /* A suitable vlan device does not already exist, add one. */
+
+ os_memset(&if_request, 0, sizeof(if_request));
+ os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
+ if_request.u.VID = vid;
+ if_request.cmd = ADD_VLAN_CMD;
+
+ if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+ wpa_printf(MSG_ERROR,
+ "VLAN: %s: ADD_VLAN_CMD failed for %s: %s",
+ __func__, if_request.device1, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+
+int vlan_set_name_type(unsigned int name_type)
+{
+ int fd;
+ struct vlan_ioctl_args if_request;
+
+ wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
+ name_type);
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+ wpa_printf(MSG_ERROR,
+ "VLAN: %s: socket(AF_INET,SOCK_STREAM) failed: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+
+ os_memset(&if_request, 0, sizeof(if_request));
+
+ if_request.u.name_type = name_type;
+ if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
+ if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+ wpa_printf(MSG_ERROR,
+ "VLAN: %s: SET_VLAN_NAME_TYPE_CMD name_type=%u failed: %s",
+ __func__, name_type, strerror(errno));
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
diff --git a/src/ap/vlan_util.c b/src/ap/vlan_util.c
index 313d89f..56d1d3d 100644
--- a/src/ap/vlan_util.c
+++ b/src/ap/vlan_util.c
@@ -7,18 +7,10 @@
*/
#include "utils/includes.h"
-#include <sys/ioctl.h>
-#include <linux/sockios.h>
-#include <linux/if_vlan.h>
-#include <netlink/genl/genl.h>
-#include <netlink/genl/family.h>
-#include <netlink/genl/ctrl.h>
#include <netlink/route/link.h>
#include <netlink/route/link/vlan.h>
#include "utils/common.h"
-#include "utils/eloop.h"
-#include "hostapd.h"
#include "vlan_util.h"
/*
@@ -174,3 +166,9 @@
nl_socket_free(handle);
return ret;
}
+
+
+int vlan_set_name_type(unsigned int name_type)
+{
+ return 0;
+}
diff --git a/src/ap/vlan_util.h b/src/ap/vlan_util.h
index bef5a16..2446859 100644
--- a/src/ap/vlan_util.h
+++ b/src/ap/vlan_util.h
@@ -1,5 +1,5 @@
/*
- * hostapd / VLAN netlink api
+ * hostapd / VLAN netlink/ioctl api
* Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de>
*
* This software may be distributed under the terms of the BSD license.
@@ -9,7 +9,23 @@
#ifndef VLAN_UTIL_H
#define VLAN_UTIL_H
+struct hostapd_data;
+struct hostapd_vlan;
+struct full_dynamic_vlan;
+
int vlan_add(const char *if_name, int vid, const char *vlan_if_name);
int vlan_rem(const char *if_name);
+int vlan_set_name_type(unsigned int name_type);
+
+int ifconfig_helper(const char *if_name, int up);
+int ifconfig_up(const char *if_name);
+int iface_exists(const char *ifname);
+int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan);
+
+struct full_dynamic_vlan *
+full_dynamic_vlan_init(struct hostapd_data *hapd);
+void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv);
+void vlan_newlink(const char *ifname, struct hostapd_data *hapd);
+void vlan_dellink(const char *ifname, struct hostapd_data *hapd);
#endif /* VLAN_UTIL_H */
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 4ded9bb..3587086 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -3359,6 +3359,46 @@
}
+int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
+ size_t len)
+{
+ if (!wpa_auth || !wpa_auth->pmksa)
+ return 0;
+ return pmksa_cache_auth_list(wpa_auth->pmksa, buf, len);
+}
+
+
+void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth)
+{
+ if (wpa_auth && wpa_auth->pmksa)
+ pmksa_cache_auth_flush(wpa_auth->pmksa);
+}
+
+
+struct rsn_pmksa_cache_entry *
+wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
+{
+ if (!wpa_auth || !wpa_auth->pmksa)
+ return NULL;
+ return pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
+}
+
+
+void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
+ struct wpa_state_machine *sm,
+ struct wpa_authenticator *wpa_auth,
+ u8 *pmkid, u8 *pmk)
+{
+ if (!sm)
+ return;
+
+ sm->pmksa = pmksa;
+ os_memcpy(pmk, pmksa->pmk, PMK_LEN);
+ os_memcpy(pmkid, pmksa->pmkid, PMKID_LEN);
+ os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmksa->pmkid, PMKID_LEN);
+}
+
+
/*
* Remove and free the group from wpa_authenticator. This is triggered by a
* callback to make sure nobody is currently iterating the group list while it
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 2b60114..0de8d97 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -298,6 +298,15 @@
const u8 *pmk, const u8 *pmkid);
void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
const u8 *sta_addr);
+int wpa_auth_pmksa_list(struct wpa_authenticator *wpa_auth, char *buf,
+ size_t len);
+void wpa_auth_pmksa_flush(struct wpa_authenticator *wpa_auth);
+struct rsn_pmksa_cache_entry *
+wpa_auth_pmksa_get(struct wpa_authenticator *wpa_auth, const u8 *sta_addr);
+void wpa_auth_pmksa_set_to_sm(struct rsn_pmksa_cache_entry *pmksa,
+ struct wpa_state_machine *sm,
+ struct wpa_authenticator *wpa_auth,
+ u8 *pmkid, u8 *pmk);
int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
struct wpa_state_machine *sm, int ack);