Coverage Report

Created: 2026-09-14 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hostap/src/ap/vlan_init.c
Line
Count
Source
1
/*
2
 * hostapd / VLAN initialization
3
 * Copyright 2003, Instant802 Networks, Inc.
4
 * Copyright 2005-2006, Devicescape Software, Inc.
5
 * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
6
 *
7
 * This software may be distributed under the terms of the BSD license.
8
 * See README for more details.
9
 */
10
11
#include "utils/includes.h"
12
13
#include "utils/common.h"
14
#include "hostapd.h"
15
#include "ap_config.h"
16
#include "ap_drv_ops.h"
17
#include "wpa_auth.h"
18
#include "vlan_init.h"
19
#include "vlan_util.h"
20
21
22
static int vlan_if_add(struct hostapd_data *hapd, struct hostapd_vlan *vlan,
23
           int existsok)
24
0
{
25
0
  int ret;
26
#ifdef CONFIG_WEP
27
  int i;
28
29
  for (i = 0; i < NUM_WEP_KEYS; i++) {
30
    if (!hapd->conf->ssid.wep.key[i])
31
      continue;
32
    wpa_printf(MSG_ERROR,
33
         "VLAN: Refusing to set up VLAN iface %s with WEP",
34
         vlan->ifname);
35
    return -1;
36
  }
37
#endif /* CONFIG_WEP */
38
39
0
  if (!iface_exists(vlan->ifname))
40
0
    ret = hostapd_vlan_if_add(hapd, vlan->ifname);
41
0
  else if (!existsok)
42
0
    return -1;
43
0
  else
44
0
    ret = 0;
45
46
0
  if (ret)
47
0
    return ret;
48
49
0
  ifconfig_up(vlan->ifname); /* else wpa group will fail fatal */
50
51
0
  if (hapd->wpa_auth)
52
0
    ret = wpa_auth_ensure_group(hapd->wpa_auth, vlan->vlan_id);
53
54
0
  if (ret == 0)
55
0
    return ret;
56
57
0
  wpa_printf(MSG_ERROR, "WPA initialization for VLAN %d failed (%d)",
58
0
       vlan->vlan_id, ret);
59
0
  if (wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id))
60
0
    wpa_printf(MSG_ERROR, "WPA deinit of %s failed", vlan->ifname);
61
62
  /* group state machine setup failed */
63
0
  if (hostapd_vlan_if_remove(hapd, vlan->ifname))
64
0
    wpa_printf(MSG_ERROR, "Removal of %s failed", vlan->ifname);
65
66
0
  return ret;
67
0
}
68
69
70
int vlan_if_remove(struct hostapd_data *hapd, struct hostapd_vlan *vlan)
71
0
{
72
0
  int ret;
73
74
0
  ret = wpa_auth_release_group(hapd->wpa_auth, vlan->vlan_id);
75
0
  if (ret)
76
0
    wpa_printf(MSG_ERROR,
77
0
         "WPA deinitialization for VLAN %d failed (%d)",
78
0
         vlan->vlan_id, ret);
79
80
0
  return hostapd_vlan_if_remove(hapd, vlan->ifname);
81
0
}
82
83
84
static int vlan_dynamic_add(struct hostapd_data *hapd,
85
          struct hostapd_vlan *vlan)
86
0
{
87
0
  while (vlan) {
88
0
    if (vlan->vlan_id != VLAN_ID_WILDCARD) {
89
0
      if (vlan_if_add(hapd, vlan, 1)) {
90
0
        wpa_printf(MSG_ERROR,
91
0
             "VLAN: Could not add VLAN %s: %s",
92
0
             vlan->ifname, strerror(errno));
93
0
        return -1;
94
0
      }
95
#ifdef CONFIG_FULL_DYNAMIC_VLAN
96
      vlan_newlink(vlan->ifname, hapd);
97
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
98
0
    }
99
100
0
    vlan = vlan->next;
101
0
  }
102
103
0
  return 0;
104
0
}
105
106
107
static void vlan_dynamic_remove(struct hostapd_data *hapd,
108
        struct hostapd_vlan *vlan)
109
0
{
110
0
  struct hostapd_vlan *next;
111
112
0
  while (vlan) {
113
0
    next = vlan->next;
114
115
#ifdef CONFIG_FULL_DYNAMIC_VLAN
116
    /* vlan_dellink() takes care of cleanup and interface removal */
117
    if (vlan->vlan_id != VLAN_ID_WILDCARD)
118
      vlan_dellink(vlan->ifname, hapd);
119
#else /* CONFIG_FULL_DYNAMIC_VLAN */
120
0
    if (vlan->vlan_id != VLAN_ID_WILDCARD &&
121
0
        vlan_if_remove(hapd, vlan)) {
122
0
      wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
123
0
           "iface: %s: %s",
124
0
           vlan->ifname, strerror(errno));
125
0
    }
126
0
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
127
128
0
    vlan = next;
129
0
  }
130
0
}
131
132
133
int vlan_init(struct hostapd_data *hapd)
134
0
{
135
#ifdef CONFIG_FULL_DYNAMIC_VLAN
136
  hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
137
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
138
139
0
  if ((hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED ||
140
0
       hapd->conf->ssid.per_sta_vif) &&
141
0
      !hapd->conf->vlan) {
142
    /* dynamic vlans enabled but no (or empty) vlan_file given */
143
0
    struct hostapd_vlan *vlan;
144
0
    int ret;
145
146
0
    vlan = os_zalloc(sizeof(*vlan));
147
0
    if (vlan == NULL) {
148
0
      wpa_printf(MSG_ERROR, "Out of memory while assigning "
149
0
           "VLAN interfaces");
150
0
      return -1;
151
0
    }
152
153
0
    vlan->vlan_id = VLAN_ID_WILDCARD;
154
0
    ret = os_snprintf(vlan->ifname, sizeof(vlan->ifname), "%s.#",
155
0
          hapd->conf->iface);
156
0
    if (ret >= (int) sizeof(vlan->ifname)) {
157
0
      wpa_printf(MSG_WARNING,
158
0
           "VLAN: Interface name was truncated to %s",
159
0
           vlan->ifname);
160
0
    } else if (ret < 0) {
161
0
      os_free(vlan);
162
0
      return ret;
163
0
    }
164
0
    vlan->next = hapd->conf->vlan;
165
0
    hapd->conf->vlan = vlan;
166
0
  }
167
168
0
  if (vlan_dynamic_add(hapd, hapd->conf->vlan))
169
0
    return -1;
170
171
0
        return 0;
172
0
}
173
174
175
void vlan_deinit(struct hostapd_data *hapd)
176
0
{
177
0
  vlan_dynamic_remove(hapd, hapd->conf->vlan);
178
179
#ifdef CONFIG_FULL_DYNAMIC_VLAN
180
  full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
181
  hapd->full_dynamic_vlan = NULL;
182
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
183
0
}
184
185
186
struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
187
               struct hostapd_vlan *vlan,
188
               int vlan_id,
189
               struct vlan_description *vlan_desc)
190
0
{
191
0
  struct hostapd_vlan *n;
192
0
  char ifname[IFNAMSIZ + 1], *pos;
193
0
  int ret;
194
195
0
  if (vlan == NULL || vlan->vlan_id != VLAN_ID_WILDCARD)
196
0
    return NULL;
197
198
0
  wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
199
0
       __func__, vlan_id, vlan->ifname);
200
0
  os_strlcpy(ifname, vlan->ifname, sizeof(ifname));
201
0
  pos = os_strchr(ifname, '#');
202
0
  if (pos == NULL)
203
0
    return NULL;
204
0
  *pos++ = '\0';
205
206
0
  n = os_zalloc(sizeof(*n));
207
0
  if (n == NULL)
208
0
    return NULL;
209
210
0
  n->vlan_id = vlan_id;
211
0
  if (vlan_desc)
212
0
    n->vlan_desc = *vlan_desc;
213
0
  n->dynamic_vlan = 1;
214
215
0
  ret = os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s",
216
0
        ifname, vlan_id, pos);
217
0
  if (os_snprintf_error(sizeof(n->ifname), ret)) {
218
0
    os_free(n);
219
0
    return NULL;
220
0
  }
221
0
  os_strlcpy(n->bridge, vlan->bridge, sizeof(n->bridge));
222
223
0
  n->next = hapd->conf->vlan;
224
0
  hapd->conf->vlan = n;
225
226
  /* hapd->conf->vlan needs this new VLAN here for WPA setup */
227
0
  if (vlan_if_add(hapd, n, 0)) {
228
0
    hapd->conf->vlan = n->next;
229
0
    os_free(n);
230
0
    n = NULL;
231
0
  }
232
233
0
  return n;
234
0
}
235
236
237
int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
238
0
{
239
0
  struct hostapd_vlan *vlan;
240
241
0
  if (vlan_id <= 0)
242
0
    return 1;
243
244
0
  wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
245
0
       __func__, hapd->conf->iface, vlan_id);
246
247
0
  vlan = hapd->conf->vlan;
248
0
  while (vlan) {
249
0
    if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
250
0
      vlan->dynamic_vlan--;
251
0
      break;
252
0
    }
253
0
    vlan = vlan->next;
254
0
  }
255
256
0
  if (vlan == NULL)
257
0
    return 1;
258
259
0
  if (vlan->dynamic_vlan == 0) {
260
0
    vlan_if_remove(hapd, vlan);
261
#ifdef CONFIG_FULL_DYNAMIC_VLAN
262
    vlan_dellink(vlan->ifname, hapd);
263
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
264
0
  }
265
266
0
  return 0;
267
0
}