[RFC 4/5] driver_nl80211: Allow bridging of AP_VLAN interfaces
Helmut Schaa
helmut.schaa
Mon Mar 17 06:16:27 PDT 2014
Signed-off-by: Helmut Schaa <helmut.schaa at googlemail.com>
---
src/drivers/driver_nl80211.c | 109 ++++++++++++++++++++++++++++++++++++-------
1 file changed, 92 insertions(+), 17 deletions(-)
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 3cfaadc..276c750 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -224,6 +224,15 @@ struct i802_bridge {
unsigned int added_bridge:1;
};
+struct i802_ap_vlan {
+ struct i802_ap_vlan *next;
+
+ int ifindex;
+ char ifname[IFNAMSIZ + 1];
+ struct i802_bridge bridge;
+ unsigned int added_if:1;
+};
+
struct i802_bss {
struct wpa_driver_nl80211_data *drv;
struct i802_bss *next;
@@ -235,6 +244,7 @@ struct i802_bss {
unsigned int wdev_id_set:1;
unsigned int added_if:1;
struct i802_bridge bridge;
+ struct i802_ap_vlan *vlans;
u8 addr[ETH_ALEN];
@@ -9743,6 +9753,35 @@ static int wpa_driver_nl80211_if_add(void *priv, enum wpa_driver_if_type type,
}
#endif /* CONFIG_P2P */
+ if (type == WPA_IF_AP_VLAN) {
+ struct i802_ap_vlan *ap_vlan = os_zalloc(sizeof(*ap_vlan));
+ if (bridge &&
+ i802_check_bridge(drv, &ap_vlan->bridge, bridge, ifname) < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to add the new "
+ "interface %s to a bridge %s",
+ ifname, bridge);
+ if (added)
+ nl80211_remove_iface(drv, ifidx);
+ os_free(ap_vlan);
+ return -1;
+ }
+
+ if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1)) {
+ if (added)
+ nl80211_remove_iface(drv, ifidx);
+ os_free(ap_vlan);
+ return -1;
+ }
+
+ ap_vlan->added_if = added;
+ ap_vlan->ifindex = ifidx;
+ os_strlcpy(ap_vlan->ifname, ifname, IFNAMSIZ);
+
+ /* Remeber this AP VLAN */
+ ap_vlan->next = bss->vlans;
+ bss->vlans = ap_vlan;
+ }
+
if (type == WPA_IF_AP_BSS) {
struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
if (new_bss == NULL) {
@@ -9799,29 +9838,65 @@ static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
{
struct wpa_driver_nl80211_data *drv = bss->drv;
int ifindex = if_nametoindex(ifname);
-
+ struct i802_bridge *bridge = NULL;
+ struct i802_ap_vlan *ap_vlan = NULL, *ap_vlan_prev = NULL;
+
wpa_printf(MSG_DEBUG, "nl80211: %s(type=%d ifname=%s) ifindex=%d added_if=%d",
__func__, type, ifname, ifindex, bss->added_if);
- if (ifindex > 0 && (bss->added_if || bss->ifindex != ifindex))
- nl80211_remove_iface(drv, ifindex);
-
- if (type != WPA_IF_AP_BSS)
- return 0;
- if (bss->bridge.added_if_into_bridge) {
- if (linux_br_del_if(drv->global->ioctl_sock, bss->bridge.brname,
- bss->ifname) < 0)
- wpa_printf(MSG_INFO, "nl80211: Failed to remove "
- "interface %s from bridge %s: %s",
- bss->ifname, bss->bridge.brname, strerror(errno));
+ switch (type) {
+ case WPA_IF_AP_BSS:
+ bridge = &bss->bridge;
+ break;
+ case WPA_IF_AP_VLAN:
+ ap_vlan = bss->vlans;
+ while (ap_vlan) {
+ if (ap_vlan->ifindex != ifindex) {
+ ap_vlan_prev = ap_vlan;
+ ap_vlan = ap_vlan->next;
+ continue;
+ }
+ bridge = &ap_vlan->bridge;
+ break;
+ }
+ break;
+ default:
+ if (ifindex > 0)
+ nl80211_remove_iface(drv, ifindex);
+ return 0;
}
- if (bss->bridge.added_bridge) {
- if (linux_br_del(drv->global->ioctl_sock, bss->bridge.brname) < 0)
- wpa_printf(MSG_INFO, "nl80211: Failed to remove "
- "bridge %s: %s",
- bss->bridge.brname, strerror(errno));
+
+ if (bridge) {
+ if (bridge->added_if_into_bridge) {
+ if (linux_br_del_if(drv->global->ioctl_sock, bridge->brname,
+ ifname) < 0)
+ wpa_printf(MSG_INFO, "nl80211: Failed to remove "
+ "interface %s from bridge %s: %s",
+ ifname, bridge->brname, strerror(errno));
+ }
+ if (bridge->added_bridge) {
+ if (linux_br_del(drv->global->ioctl_sock, bridge->brname) < 0)
+ wpa_printf(MSG_INFO, "nl80211: Failed to remove "
+ "bridge %s: %s",
+ bridge->brname, strerror(errno));
+ }
}
+ if (ap_vlan) {
+ if (ap_vlan->added_if && ap_vlan->ifindex == ifindex)
+ nl80211_remove_iface(drv, ifindex);
+ if (ap_vlan_prev)
+ ap_vlan_prev->next = ap_vlan->next;
+ else
+ bss->vlans = ap_vlan->next;
+
+ os_free(ap_vlan);
+ return 0;
+ }
+
+ if (bss->added_if)
+ nl80211_remove_iface(drv, ifindex);
+
if (bss != drv->first_bss) {
struct i802_bss *tbss;
--
1.8.1.4
More information about the Hostap
mailing list