+int ap_sta_set_vlan(struct hostapd_data *hapd, struct sta_info *sta,
+ struct vlan_description *vlan_desc)
+{
+ struct hostapd_vlan *vlan = NULL, *wildcard_vlan = NULL;
+ int old_vlan_id, vlan_id = 0, ret = 0;
+
+ if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED) {
+ vlan_desc = NULL;
+ } else if (vlan_desc && vlan_desc->notempty) {
+ if (!vlan_compare(vlan_desc, sta->vlan_desc))
+ return 0; /* nothing to change */
+
+ for (vlan = hapd->conf->vlan; vlan; vlan = vlan->next) {
+ if (!vlan_compare(&vlan->vlan_desc, vlan_desc))
+ break;
+ if (vlan->vlan_id == VLAN_ID_WILDCARD)
+ wildcard_vlan = vlan;
+ }
+ if (vlan) {
+ vlan_id = vlan->vlan_id;
+ } else if (wildcard_vlan) {
+ vlan = wildcard_vlan;
+ vlan_id = vlan_desc->untagged;
+ } else {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "missing VLAN and wildcard for vlan=%d",
+ vlan_desc->untagged);
+ vlan_id = 0;
+ ret = -1;
+ goto done;
+ }
+ }
+
+ if (vlan && vlan->vlan_id == VLAN_ID_WILDCARD) {
+ vlan = vlan_add_dynamic(hapd, vlan, vlan_id, vlan_desc);
+ if (vlan == NULL) {
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "could not add dynamic VLAN interface for vlan=%d",
+ vlan_desc->untagged);
+ vlan_id = 0;
+ ret = -1;
+ goto done;
+ }
+
+ hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "added new dynamic VLAN interface '%s'",
+ vlan->ifname);
+ } else if (vlan && vlan->dynamic_vlan > 0) {
+ vlan->dynamic_vlan++;
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "updated existing dynamic VLAN interface '%s'",
+ vlan->ifname);
+ }
+done:
+ old_vlan_id = sta->vlan_id;
+ sta->vlan_id = vlan_id;
+ sta->vlan_desc = vlan ? &vlan->vlan_desc : NULL;
+
+ if (vlan_id != old_vlan_id && old_vlan_id)
+ vlan_remove_dynamic(hapd, old_vlan_id);
+
+ return ret;
+}
+
+