mac80211: fix a race condition when bringing up wds sta interfaces on the ap
[openwrt.git] / package / hostapd / patches / 130-wds_ap.patch
1 --- a/hostapd/config.c
2 +++ b/hostapd/config.c
3 @@ -1526,6 +1526,8 @@ struct hostapd_config * hostapd_config_r
4                                            line, pos);
5                                 errors++;
6                         }
7 +               } else if (os_strcmp(buf, "wds_sta") == 0) {
8 +                       bss->wds_sta = atoi(pos);
9                 } else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
10                         bss->ap_max_inactivity = atoi(pos);
11                 } else if (os_strcmp(buf, "country_code") == 0) {
12 --- a/hostapd/config.h
13 +++ b/hostapd/config.h
14 @@ -198,6 +198,7 @@ struct hostapd_bss_config {
15         int num_accept_mac;
16         struct mac_acl_entry *deny_mac;
17         int num_deny_mac;
18 +       int wds_sta;
19  
20         int auth_algs; /* bitfield of allowed IEEE 802.11 authentication
21                         * algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
22 --- a/src/drivers/driver.h
23 +++ b/src/drivers/driver.h
24 @@ -1305,6 +1305,7 @@ struct wpa_driver_ops {
25                          const char *ifname, const u8 *addr);
26         int (*set_sta_vlan)(void *priv, const u8 *addr, const char *ifname,
27                             int vlan_id);
28 +       int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val);
29         /**
30          * commit - Optional commit changes handler
31          * @priv: driver private data
32 --- a/src/drivers/driver_nl80211.c
33 +++ b/src/drivers/driver_nl80211.c
34 @@ -2755,7 +2755,7 @@ static void nl80211_remove_iface(struct 
35  static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
36                                      const char *ifname,
37                                      enum nl80211_iftype iftype,
38 -                                    const u8 *addr)
39 +                                    const u8 *addr, int wds)
40  {
41         struct nl_msg *msg, *flags = NULL;
42         int ifidx;
43 @@ -2786,6 +2786,8 @@ static int nl80211_create_iface_once(str
44  
45                 if (err)
46                         goto nla_put_failure;
47 +       } else if (wds) {
48 +               NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
49         }
50  
51         ret = send_and_recv_msgs(drv, msg, NULL, NULL);
52 @@ -2816,11 +2818,11 @@ static int nl80211_create_iface_once(str
53  }
54  static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
55                                 const char *ifname, enum nl80211_iftype iftype,
56 -                               const u8 *addr)
57 +                               const u8 *addr, int wds)
58  {
59         int ret;
60  
61 -       ret = nl80211_create_iface_once(drv, ifname, iftype, addr);
62 +       ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
63  
64         /* if error occured and interface exists already */
65         if (ret == -ENFILE && if_nametoindex(ifname)) {
66 @@ -2830,7 +2832,7 @@ static int nl80211_create_iface(struct w
67                 nl80211_remove_iface(drv, if_nametoindex(ifname));
68  
69                 /* Try to create the interface again */
70 -               ret = nl80211_create_iface_once(drv, ifname, iftype, addr);
71 +               ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
72         }
73  
74         return ret;
75 @@ -3055,7 +3057,7 @@ static struct sock_filter msock_filter_i
76  
77  #if 0
78         /*
79 -        * drop non-data frames, WDS frames
80 +        * drop non-data frames
81          */
82         /* load the lower byte of the frame control field */
83         BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 0),
84 @@ -3063,13 +3065,13 @@ static struct sock_filter msock_filter_i
85         BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x0c),
86         /* drop non-data frames */
87         BPF_JUMP(BPF_JMP  | BPF_JEQ | BPF_K, 8, 0, FAIL),
88 +#endif
89         /* load the upper byte of the frame control field */
90 -       BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 0),
91 +       BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 1),
92         /* mask off toDS/fromDS */
93         BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x03),
94 -       /* drop WDS frames */
95 -       BPF_JUMP(BPF_JMP  | BPF_JEQ | BPF_K, 3, FAIL, 0),
96 -#endif
97 +       /* accept WDS frames */
98 +       BPF_JUMP(BPF_JMP  | BPF_JEQ | BPF_K, 3, PASS, 0),
99  
100         /*
101          * add header length to index
102 @@ -3175,7 +3177,7 @@ nl80211_create_monitor_interface(struct 
103         buf[IFNAMSIZ - 1] = '\0';
104  
105         drv->monitor_ifidx =
106 -               nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL);
107 +               nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL, 0);
108  
109         if (drv->monitor_ifidx < 0)
110                 return -1;
111 @@ -4155,7 +4157,7 @@ static int i802_bss_add(void *priv, cons
112         if (bss == NULL)
113                 return -1;
114  
115 -       ifidx = nl80211_create_iface(priv, ifname, NL80211_IFTYPE_AP, bssid);
116 +       ifidx = nl80211_create_iface(priv, ifname, NL80211_IFTYPE_AP, bssid, 0);
117         if (ifidx < 0) {
118                 os_free(bss);
119                 return -1;
120 @@ -4264,7 +4266,7 @@ static int i802_if_add(const char *iface
121                        enum hostapd_driver_if_type type, char *ifname,
122                        const u8 *addr)
123  {
124 -       if (nl80211_create_iface(priv, ifname, i802_if_type(type), addr) < 0)
125 +       if (nl80211_create_iface(priv, ifname, i802_if_type(type), addr, 0) < 0)
126                 return -1;
127         return 0;
128  }
129 @@ -4310,6 +4312,22 @@ static int i802_set_sta_vlan(void *priv,
130         return -ENOBUFS;
131  }
132  
133 +static int i802_set_wds_sta(void *priv, const u8 *addr, int aid, int val)
134 +{
135 +       struct wpa_driver_nl80211_data *drv = priv;
136 +       char name[16];
137 +
138 +       sprintf(name, "%s.sta%d", drv->ifname, aid);
139 +       if (val) {
140 +               if (nl80211_create_iface(priv, name, NL80211_IFTYPE_AP_VLAN, NULL, 1) < 0)
141 +                       return -1;
142 +               hostapd_set_iface_flags(drv, name, 1);
143 +               return i802_set_sta_vlan(priv, addr, name, 0);
144 +       } else {
145 +               i802_set_sta_vlan(priv, addr, drv->ifname, 0);
146 +               return i802_if_remove(priv, HOSTAPD_IF_VLAN, name, NULL);
147 +       }
148 +}
149  
150  static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
151  {
152 @@ -4536,5 +4554,6 @@ const struct wpa_driver_ops wpa_driver_n
153         .if_update = i802_if_update,
154         .if_remove = i802_if_remove,
155         .set_sta_vlan = i802_set_sta_vlan,
156 +       .set_wds_sta = i802_set_wds_sta,
157  #endif /* HOSTAPD */
158  };
159 --- a/hostapd/driver_i.h
160 +++ b/hostapd/driver_i.h
161 @@ -453,6 +453,14 @@ hostapd_set_sta_vlan(const char *ifname,
162  }
163  
164  static inline int
165 +hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid, int val)
166 +{
167 +       if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL)
168 +               return 0;
169 +       return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val);
170 +}
171 +
172 +static inline int
173  hostapd_driver_commit(struct hostapd_data *hapd)
174  {
175         if (hapd->driver == NULL || hapd->driver->commit == NULL)
176 --- a/hostapd/drv_callbacks.c
177 +++ b/hostapd/drv_callbacks.c
178 @@ -167,6 +167,7 @@ static const u8 * get_hdr_bssid(const st
179                 if (len < 24)
180                         return NULL;
181                 switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
182 +               case WLAN_FC_FROMDS|WLAN_FC_TODS:
183                 case WLAN_FC_TODS:
184                         return hdr->addr1;
185                 case WLAN_FC_FROMDS:
186 @@ -213,6 +214,7 @@ void hostapd_rx_from_unknown_sta(struct 
187  {
188         struct sta_info *sta;
189         const u8 *addr;
190 +       u16 fc = le_to_host16(hdr->frame_control);
191  
192         hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
193         if (hapd == NULL || hapd == HAPD_BROADCAST)
194 @@ -231,6 +233,14 @@ void hostapd_rx_from_unknown_sta(struct 
195                         hostapd_sta_deauth(
196                                 hapd, addr,
197                                 WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
198 +       } else {
199 +               if (!sta->wds_sta) {
200 +                       if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
201 +                           (WLAN_FC_TODS | WLAN_FC_FROMDS)) {
202 +                               sta->wds_sta = 1;
203 +                               hostapd_set_wds_sta(hapd, addr, sta->aid, 1);
204 +                       }
205 +               }
206         }
207  }
208  
209 --- a/hostapd/sta_info.c
210 +++ b/hostapd/sta_info.c
211 @@ -120,6 +120,7 @@ void ap_free_sta(struct hostapd_data *ha
212  
213         accounting_sta_stop(hapd, sta);
214  
215 +       hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 0);
216         if (!ap_sta_in_other_bss(hapd, sta, WLAN_STA_ASSOC) &&
217             !(sta->flags & WLAN_STA_PREAUTH))
218                 hostapd_sta_remove(hapd, sta->addr);
219 --- a/hostapd/sta_info.h
220 +++ b/hostapd/sta_info.h
221 @@ -78,6 +78,7 @@ struct sta_info {
222         struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
223  
224         int vlan_id;
225 +       int wds_sta;
226  
227  #ifdef CONFIG_IEEE80211N
228         struct ht_cap_ie ht_capabilities; /* IEEE 802.11n capabilities */
229 --- a/src/common/nl80211_copy.h
230 +++ b/src/common/nl80211_copy.h
231 @@ -584,6 +584,8 @@ enum nl80211_commands {
232   *     changed then the list changed and the dump should be repeated
233   *     completely from scratch.
234   *
235 + * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface
236 + *
237   * @NL80211_ATTR_MAX: highest attribute number currently defined
238   * @__NL80211_ATTR_AFTER_LAST: internal use
239   */
240 @@ -714,6 +716,8 @@ enum nl80211_attrs {
241  
242         NL80211_ATTR_PID,
243  
244 +       NL80211_ATTR_4ADDR,
245 +
246         /* add attributes here, update the policy in nl80211.c */
247  
248         __NL80211_ATTR_AFTER_LAST,