13ff40c12SJohn Marino /*
23ff40c12SJohn Marino * hostapd / VLAN initialization
33ff40c12SJohn Marino * Copyright 2003, Instant802 Networks, Inc.
43ff40c12SJohn Marino * Copyright 2005-2006, Devicescape Software, Inc.
53ff40c12SJohn Marino * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
63ff40c12SJohn Marino *
73ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license.
83ff40c12SJohn Marino * See README for more details.
93ff40c12SJohn Marino */
103ff40c12SJohn Marino
113ff40c12SJohn Marino #include "utils/includes.h"
123ff40c12SJohn Marino
133ff40c12SJohn Marino #include "utils/common.h"
143ff40c12SJohn Marino #include "hostapd.h"
153ff40c12SJohn Marino #include "ap_config.h"
163ff40c12SJohn Marino #include "ap_drv_ops.h"
17*a1157835SDaniel Fojt #include "wpa_auth.h"
183ff40c12SJohn Marino #include "vlan_init.h"
193ff40c12SJohn Marino #include "vlan_util.h"
203ff40c12SJohn Marino
213ff40c12SJohn Marino
vlan_if_add(struct hostapd_data * hapd,struct hostapd_vlan * vlan,int existsok)22*a1157835SDaniel Fojt static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
23*a1157835SDaniel Fojt int existsok)
243ff40c12SJohn Marino {
25*a1157835SDaniel Fojt int ret, i;
263ff40c12SJohn Marino
27*a1157835SDaniel Fojt for (i = 0; i < NUM_WEP_KEYS; i++) {
28*a1157835SDaniel Fojt if (!hapd->conf->ssid.wep.key[i])
29*a1157835SDaniel Fojt continue;
30*a1157835SDaniel Fojt wpa_printf(MSG_ERROR,
31*a1157835SDaniel Fojt "VLAN: Refusing to set up VLAN iface %s with WEP",
32*a1157835SDaniel Fojt vlan->ifname);
333ff40c12SJohn Marino return -1;
343ff40c12SJohn Marino }
353ff40c12SJohn Marino
36*a1157835SDaniel Fojt if (!iface_exists(vlan->ifname))
37*a1157835SDaniel Fojt ret = hostapd_vlan_if_add(hapd, vlan->ifname);
38*a1157835SDaniel Fojt else if (!existsok)
393ff40c12SJohn Marino return -1;
403ff40c12SJohn Marino else
41*a1157835SDaniel Fojt ret = 0;
423ff40c12SJohn Marino
43*a1157835SDaniel Fojt if (ret)
44*a1157835SDaniel Fojt return ret;
453ff40c12SJohn Marino
46*a1157835SDaniel Fojt ifconfig_up(vlan->ifname); /* else wpa group will fail fatal */
47*a1157835SDaniel Fojt
48*a1157835SDaniel Fojt if (hapd->wpa_auth)
49*a1157835SDaniel Fojt ret = wpa_auth_ensure_group(hapd->wpa_auth, vlan->vlan_id);
50*a1157835SDaniel Fojt
51*a1157835SDaniel Fojt if (ret == 0)
52*a1157835SDaniel Fojt return ret;
53*a1157835SDaniel Fojt
54*a1157835SDaniel Fojt wpa_printf(MSG_ERROR, "WPA initialization for VLAN %d failed (%d)",
55*a1157835SDaniel Fojt vlan->vlan_id, ret);
56*a1157835SDaniel Fojt if (wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id))
57*a1157835SDaniel Fojt wpa_printf(MSG_ERROR, "WPA deinit of %s failed", vlan->ifname);
58*a1157835SDaniel Fojt
59*a1157835SDaniel Fojt /* group state machine setup failed */
60*a1157835SDaniel Fojt if (hostapd_vlan_if_remove(hapd, vlan->ifname))
61*a1157835SDaniel Fojt wpa_printf(MSG_ERROR, "Removal of %s failed", vlan->ifname);
62*a1157835SDaniel Fojt
63*a1157835SDaniel Fojt return ret;
643ff40c12SJohn Marino }
653ff40c12SJohn Marino
663ff40c12SJohn Marino
vlan_if_remove(struct hostapd_data * hapd,struct hostapd_vlan * vlan)67*a1157835SDaniel Fojt int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
683ff40c12SJohn Marino {
693ff40c12SJohn Marino int ret;
703ff40c12SJohn Marino
71*a1157835SDaniel Fojt ret = wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id);
72*a1157835SDaniel Fojt if (ret)
73*a1157835SDaniel Fojt wpa_printf(MSG_ERROR,
74*a1157835SDaniel Fojt "WPA deinitialization for VLAN %d failed (%d)",
75*a1157835SDaniel Fojt vlan->vlan_id, ret);
763ff40c12SJohn Marino
77*a1157835SDaniel Fojt return hostapd_vlan_if_remove(hapd, vlan->ifname);
783ff40c12SJohn Marino }
793ff40c12SJohn Marino
803ff40c12SJohn Marino
vlan_dynamic_add(struct hostapd_data * hapd,struct hostapd_vlan * vlan)813ff40c12SJohn Marino static int vlan_dynamic_add(struct hostapd_data *hapd,
823ff40c12SJohn Marino struct hostapd_vlan *vlan)
833ff40c12SJohn Marino {
843ff40c12SJohn Marino while (vlan) {
853ff40c12SJohn Marino if (vlan->vlan_id != VLAN_ID_WILDCARD) {
86*a1157835SDaniel Fojt if (vlan_if_add(hapd, vlan, 1)) {
87*a1157835SDaniel Fojt wpa_printf(MSG_ERROR,
88*a1157835SDaniel Fojt "VLAN: Could not add VLAN %s: %s",
89*a1157835SDaniel Fojt vlan->ifname, strerror(errno));
903ff40c12SJohn Marino return -1;
913ff40c12SJohn Marino }
923ff40c12SJohn Marino #ifdef CONFIG_FULL_DYNAMIC_VLAN
93*a1157835SDaniel Fojt vlan_newlink(vlan->ifname, hapd);
943ff40c12SJohn Marino #endif /* CONFIG_FULL_DYNAMIC_VLAN */
953ff40c12SJohn Marino }
963ff40c12SJohn Marino
973ff40c12SJohn Marino vlan = vlan->next;
983ff40c12SJohn Marino }
993ff40c12SJohn Marino
1003ff40c12SJohn Marino return 0;
1013ff40c12SJohn Marino }
1023ff40c12SJohn Marino
1033ff40c12SJohn Marino
vlan_dynamic_remove(struct hostapd_data * hapd,struct hostapd_vlan * vlan)1043ff40c12SJohn Marino static void vlan_dynamic_remove(struct hostapd_data *hapd,
1053ff40c12SJohn Marino struct hostapd_vlan *vlan)
1063ff40c12SJohn Marino {
1073ff40c12SJohn Marino struct hostapd_vlan *next;
1083ff40c12SJohn Marino
1093ff40c12SJohn Marino while (vlan) {
1103ff40c12SJohn Marino next = vlan->next;
1113ff40c12SJohn Marino
112*a1157835SDaniel Fojt #ifdef CONFIG_FULL_DYNAMIC_VLAN
113*a1157835SDaniel Fojt /* vlan_dellink() takes care of cleanup and interface removal */
114*a1157835SDaniel Fojt if (vlan->vlan_id != VLAN_ID_WILDCARD)
115*a1157835SDaniel Fojt vlan_dellink(vlan->ifname, hapd);
116*a1157835SDaniel Fojt #else /* CONFIG_FULL_DYNAMIC_VLAN */
1173ff40c12SJohn Marino if (vlan->vlan_id != VLAN_ID_WILDCARD &&
118*a1157835SDaniel Fojt vlan_if_remove(hapd, vlan)) {
1193ff40c12SJohn Marino wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
1203ff40c12SJohn Marino "iface: %s: %s",
1213ff40c12SJohn Marino vlan->ifname, strerror(errno));
1223ff40c12SJohn Marino }
1233ff40c12SJohn Marino #endif /* CONFIG_FULL_DYNAMIC_VLAN */
1243ff40c12SJohn Marino
1253ff40c12SJohn Marino vlan = next;
1263ff40c12SJohn Marino }
1273ff40c12SJohn Marino }
1283ff40c12SJohn Marino
1293ff40c12SJohn Marino
vlan_init(struct hostapd_data * hapd)1303ff40c12SJohn Marino int vlan_init(struct hostapd_data *hapd)
1313ff40c12SJohn Marino {
1323ff40c12SJohn Marino #ifdef CONFIG_FULL_DYNAMIC_VLAN
1333ff40c12SJohn Marino hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
1343ff40c12SJohn Marino #endif /* CONFIG_FULL_DYNAMIC_VLAN */
1353ff40c12SJohn Marino
136*a1157835SDaniel Fojt if ((hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED ||
137*a1157835SDaniel Fojt hapd->conf->ssid.per_sta_vif) &&
1383ff40c12SJohn Marino !hapd->conf->vlan) {
1393ff40c12SJohn Marino /* dynamic vlans enabled but no (or empty) vlan_file given */
1403ff40c12SJohn Marino struct hostapd_vlan *vlan;
141*a1157835SDaniel Fojt int ret;
142*a1157835SDaniel Fojt
1433ff40c12SJohn Marino vlan = os_zalloc(sizeof(*vlan));
1443ff40c12SJohn Marino if (vlan == NULL) {
1453ff40c12SJohn Marino wpa_printf(MSG_ERROR, "Out of memory while assigning "
1463ff40c12SJohn Marino "VLAN interfaces");
1473ff40c12SJohn Marino return -1;
1483ff40c12SJohn Marino }
1493ff40c12SJohn Marino
1503ff40c12SJohn Marino vlan->vlan_id = VLAN_ID_WILDCARD;
151*a1157835SDaniel Fojt ret = os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
1523ff40c12SJohn Marino hapd->conf->iface);
153*a1157835SDaniel Fojt if (ret >= (int) sizeof(vlan->ifname)) {
154*a1157835SDaniel Fojt wpa_printf(MSG_WARNING,
155*a1157835SDaniel Fojt "VLAN: Interface name was truncated to %s",
156*a1157835SDaniel Fojt vlan->ifname);
157*a1157835SDaniel Fojt } else if (ret < 0) {
158*a1157835SDaniel Fojt os_free(vlan);
159*a1157835SDaniel Fojt return ret;
160*a1157835SDaniel Fojt }
1613ff40c12SJohn Marino vlan->next = hapd->conf->vlan;
1623ff40c12SJohn Marino hapd->conf->vlan = vlan;
1633ff40c12SJohn Marino }
1643ff40c12SJohn Marino
1653ff40c12SJohn Marino if (vlan_dynamic_add(hapd, hapd->conf->vlan))
1663ff40c12SJohn Marino return -1;
1673ff40c12SJohn Marino
1683ff40c12SJohn Marino return 0;
1693ff40c12SJohn Marino }
1703ff40c12SJohn Marino
1713ff40c12SJohn Marino
vlan_deinit(struct hostapd_data * hapd)1723ff40c12SJohn Marino void vlan_deinit(struct hostapd_data *hapd)
1733ff40c12SJohn Marino {
1743ff40c12SJohn Marino vlan_dynamic_remove(hapd, hapd->conf->vlan);
1753ff40c12SJohn Marino
1763ff40c12SJohn Marino #ifdef CONFIG_FULL_DYNAMIC_VLAN
1773ff40c12SJohn Marino full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
1783ff40c12SJohn Marino hapd->full_dynamic_vlan = NULL;
1793ff40c12SJohn Marino #endif /* CONFIG_FULL_DYNAMIC_VLAN */
1803ff40c12SJohn Marino }
1813ff40c12SJohn Marino
1823ff40c12SJohn Marino
vlan_add_dynamic(struct hostapd_data * hapd,struct hostapd_vlan * vlan,int vlan_id,struct vlan_description * vlan_desc)1833ff40c12SJohn Marino struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
1843ff40c12SJohn Marino struct hostapd_vlan *vlan,
185*a1157835SDaniel Fojt int vlan_id,
186*a1157835SDaniel Fojt struct vlan_description *vlan_desc)
1873ff40c12SJohn Marino {
1883ff40c12SJohn Marino struct hostapd_vlan *n;
189*a1157835SDaniel Fojt char ifname[IFNAMSIZ + 1], *pos;
190*a1157835SDaniel Fojt int ret;
1913ff40c12SJohn Marino
192*a1157835SDaniel Fojt if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD)
1933ff40c12SJohn Marino return NULL;
1943ff40c12SJohn Marino
1953ff40c12SJohn Marino wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
1963ff40c12SJohn Marino __func__, vlan_id, vlan->ifname);
197*a1157835SDaniel Fojt os_strlcpy(ifname, vlan->ifname, sizeof(ifname));
1983ff40c12SJohn Marino pos = os_strchr(ifname, '#');
199*a1157835SDaniel Fojt if (pos == NULL)
2003ff40c12SJohn Marino return NULL;
2013ff40c12SJohn Marino *pos++ = '\0';
2023ff40c12SJohn Marino
2033ff40c12SJohn Marino n = os_zalloc(sizeof(*n));
204*a1157835SDaniel Fojt if (n == NULL)
2053ff40c12SJohn Marino return NULL;
2063ff40c12SJohn Marino
2073ff40c12SJohn Marino n->vlan_id = vlan_id;
208*a1157835SDaniel Fojt if (vlan_desc)
209*a1157835SDaniel Fojt n->vlan_desc = *vlan_desc;
2103ff40c12SJohn Marino n->dynamic_vlan = 1;
2113ff40c12SJohn Marino
212*a1157835SDaniel Fojt ret = os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s",
213*a1157835SDaniel Fojt ifname, vlan_id, pos);
214*a1157835SDaniel Fojt if (os_snprintf_error(sizeof(n->ifname), ret)) {
2153ff40c12SJohn Marino os_free(n);
2163ff40c12SJohn Marino return NULL;
2173ff40c12SJohn Marino }
218*a1157835SDaniel Fojt os_strlcpy(n->bridge, vlan->bridge, sizeof(n->bridge));
2193ff40c12SJohn Marino
2203ff40c12SJohn Marino n->next = hapd->conf->vlan;
2213ff40c12SJohn Marino hapd->conf->vlan = n;
2223ff40c12SJohn Marino
223*a1157835SDaniel Fojt /* hapd->conf->vlan needs this new VLAN here for WPA setup */
224*a1157835SDaniel Fojt if (vlan_if_add(hapd, n, 0)) {
225*a1157835SDaniel Fojt hapd->conf->vlan = n->next;
226*a1157835SDaniel Fojt os_free(n);
227*a1157835SDaniel Fojt n = NULL;
228*a1157835SDaniel Fojt }
2293ff40c12SJohn Marino
2303ff40c12SJohn Marino return n;
2313ff40c12SJohn Marino }
2323ff40c12SJohn Marino
2333ff40c12SJohn Marino
vlan_remove_dynamic(struct hostapd_data * hapd,int vlan_id)2343ff40c12SJohn Marino int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
2353ff40c12SJohn Marino {
2363ff40c12SJohn Marino struct hostapd_vlan *vlan;
2373ff40c12SJohn Marino
238*a1157835SDaniel Fojt if (vlan_id <= 0)
2393ff40c12SJohn Marino return 1;
2403ff40c12SJohn Marino
241*a1157835SDaniel Fojt wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
242*a1157835SDaniel Fojt __func__, hapd->conf->iface, vlan_id);
2433ff40c12SJohn Marino
2443ff40c12SJohn Marino vlan = hapd->conf->vlan;
2453ff40c12SJohn Marino while (vlan) {
2463ff40c12SJohn Marino if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
2473ff40c12SJohn Marino vlan->dynamic_vlan--;
2483ff40c12SJohn Marino break;
2493ff40c12SJohn Marino }
2503ff40c12SJohn Marino vlan = vlan->next;
2513ff40c12SJohn Marino }
2523ff40c12SJohn Marino
2533ff40c12SJohn Marino if (vlan == NULL)
2543ff40c12SJohn Marino return 1;
2553ff40c12SJohn Marino
256*a1157835SDaniel Fojt if (vlan->dynamic_vlan == 0) {
257*a1157835SDaniel Fojt vlan_if_remove(hapd, vlan);
258*a1157835SDaniel Fojt #ifdef CONFIG_FULL_DYNAMIC_VLAN
259*a1157835SDaniel Fojt vlan_dellink(vlan->ifname, hapd);
260*a1157835SDaniel Fojt #endif /* CONFIG_FULL_DYNAMIC_VLAN */
261*a1157835SDaniel Fojt }
2623ff40c12SJohn Marino
2633ff40c12SJohn Marino return 0;
2643ff40c12SJohn Marino }
265