Commit 239281f803e2efdb77d906ef296086b6917e5d71
Committed by
Johannes Berg
1 parent
6e0bd6c35b
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
mac80211: 802.11p OCB mode support
This patch adds 802.11p OCB (Outside the Context of a BSS) mode support. When communicating in OCB mode a mandatory wildcard BSSID (48 '1' bits) is used. The EDCA parameters handling function was changed to support 802.11p specific values. The insertion of a newly discovered STAs is done in the similar way as in the IBSS mode -- through the deferred insertion. The OCB mode uses a periodic 'housekeeping task' for expiration of disconnected STAs (in the similar manner as in the MESH mode). New Kconfig option for verbose OCB debugging outputs is added. Signed-off-by: Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Showing 14 changed files with 417 additions and 9 deletions Side-by-side Diff
include/net/mac80211.h
... | ... | @@ -263,6 +263,7 @@ |
263 | 263 | * @BSS_CHANGED_BANDWIDTH: The bandwidth used by this interface changed, |
264 | 264 | * note that this is only called when it changes after the channel |
265 | 265 | * context had been assigned. |
266 | + * @BSS_CHANGED_OCB: OCB join status changed | |
266 | 267 | */ |
267 | 268 | enum ieee80211_bss_change { |
268 | 269 | BSS_CHANGED_ASSOC = 1<<0, |
... | ... | @@ -287,6 +288,7 @@ |
287 | 288 | BSS_CHANGED_P2P_PS = 1<<19, |
288 | 289 | BSS_CHANGED_BEACON_INFO = 1<<20, |
289 | 290 | BSS_CHANGED_BANDWIDTH = 1<<21, |
291 | + BSS_CHANGED_OCB = 1<<22, | |
290 | 292 | |
291 | 293 | /* when adding here, make sure to change ieee80211_reconfig */ |
292 | 294 | }; |
net/mac80211/Kconfig
... | ... | @@ -176,6 +176,17 @@ |
176 | 176 | |
177 | 177 | Do not select this option. |
178 | 178 | |
179 | +config MAC80211_OCB_DEBUG | |
180 | + bool "Verbose OCB debugging" | |
181 | + depends on MAC80211_DEBUG_MENU | |
182 | + ---help--- | |
183 | + Selecting this option causes mac80211 to print out | |
184 | + very verbose OCB debugging messages. It should not | |
185 | + be selected on production systems as those messages | |
186 | + are remotely triggerable. | |
187 | + | |
188 | + Do not select this option. | |
189 | + | |
179 | 190 | config MAC80211_IBSS_DEBUG |
180 | 191 | bool "Verbose IBSS debugging" |
181 | 192 | depends on MAC80211_DEBUG_MENU |
net/mac80211/Makefile
net/mac80211/cfg.c
... | ... | @@ -2019,6 +2019,17 @@ |
2019 | 2019 | return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev)); |
2020 | 2020 | } |
2021 | 2021 | |
2022 | +static int ieee80211_join_ocb(struct wiphy *wiphy, struct net_device *dev, | |
2023 | + struct ocb_setup *setup) | |
2024 | +{ | |
2025 | + return ieee80211_ocb_join(IEEE80211_DEV_TO_SUB_IF(dev), setup); | |
2026 | +} | |
2027 | + | |
2028 | +static int ieee80211_leave_ocb(struct wiphy *wiphy, struct net_device *dev) | |
2029 | +{ | |
2030 | + return ieee80211_ocb_leave(IEEE80211_DEV_TO_SUB_IF(dev)); | |
2031 | +} | |
2032 | + | |
2022 | 2033 | static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev, |
2023 | 2034 | int rate[IEEE80211_NUM_BANDS]) |
2024 | 2035 | { |
... | ... | @@ -3693,6 +3704,8 @@ |
3693 | 3704 | .join_mesh = ieee80211_join_mesh, |
3694 | 3705 | .leave_mesh = ieee80211_leave_mesh, |
3695 | 3706 | #endif |
3707 | + .join_ocb = ieee80211_join_ocb, | |
3708 | + .leave_ocb = ieee80211_leave_ocb, | |
3696 | 3709 | .change_bss = ieee80211_change_bss, |
3697 | 3710 | .set_txq_params = ieee80211_set_txq_params, |
3698 | 3711 | .set_monitor_channel = ieee80211_set_monitor_channel, |
net/mac80211/chan.c
net/mac80211/debug.h
... | ... | @@ -2,6 +2,12 @@ |
2 | 2 | #define __MAC80211_DEBUG_H |
3 | 3 | #include <net/cfg80211.h> |
4 | 4 | |
5 | +#ifdef CONFIG_MAC80211_OCB_DEBUG | |
6 | +#define MAC80211_OCB_DEBUG 1 | |
7 | +#else | |
8 | +#define MAC80211_OCB_DEBUG 0 | |
9 | +#endif | |
10 | + | |
5 | 11 | #ifdef CONFIG_MAC80211_IBSS_DEBUG |
6 | 12 | #define MAC80211_IBSS_DEBUG 1 |
7 | 13 | #else |
... | ... | @@ -129,6 +135,10 @@ |
129 | 135 | |
130 | 136 | #define ht_dbg_ratelimited(sdata, fmt, ...) \ |
131 | 137 | _sdata_dbg(MAC80211_HT_DEBUG && net_ratelimit(), \ |
138 | + sdata, fmt, ##__VA_ARGS__) | |
139 | + | |
140 | +#define ocb_dbg(sdata, fmt, ...) \ | |
141 | + _sdata_dbg(MAC80211_OCB_DEBUG, \ | |
132 | 142 | sdata, fmt, ##__VA_ARGS__) |
133 | 143 | |
134 | 144 | #define ibss_dbg(sdata, fmt, ...) \ |
net/mac80211/driver-ops.h
... | ... | @@ -214,7 +214,8 @@ |
214 | 214 | BSS_CHANGED_BEACON_ENABLED) && |
215 | 215 | sdata->vif.type != NL80211_IFTYPE_AP && |
216 | 216 | sdata->vif.type != NL80211_IFTYPE_ADHOC && |
217 | - sdata->vif.type != NL80211_IFTYPE_MESH_POINT)) | |
217 | + sdata->vif.type != NL80211_IFTYPE_MESH_POINT && | |
218 | + sdata->vif.type != NL80211_IFTYPE_OCB)) | |
218 | 219 | return; |
219 | 220 | |
220 | 221 | if (WARN_ON_ONCE(sdata->vif.type == NL80211_IFTYPE_P2P_DEVICE || |
net/mac80211/ieee80211_i.h
... | ... | @@ -577,6 +577,25 @@ |
577 | 577 | }; |
578 | 578 | |
579 | 579 | /** |
580 | + * struct ieee80211_if_ocb - OCB mode state | |
581 | + * | |
582 | + * @housekeeping_timer: timer for periodic invocation of a housekeeping task | |
583 | + * @wrkq_flags: OCB deferred task action | |
584 | + * @incomplete_lock: delayed STA insertion lock | |
585 | + * @incomplete_stations: list of STAs waiting for delayed insertion | |
586 | + * @joined: indication if the interface is connected to an OCB network | |
587 | + */ | |
588 | +struct ieee80211_if_ocb { | |
589 | + struct timer_list housekeeping_timer; | |
590 | + unsigned long wrkq_flags; | |
591 | + | |
592 | + spinlock_t incomplete_lock; | |
593 | + struct list_head incomplete_stations; | |
594 | + | |
595 | + bool joined; | |
596 | +}; | |
597 | + | |
598 | +/** | |
580 | 599 | * struct ieee80211_mesh_sync_ops - Extensible synchronization framework interface |
581 | 600 | * |
582 | 601 | * these declarations define the interface, which enables |
... | ... | @@ -869,6 +888,7 @@ |
869 | 888 | struct ieee80211_if_managed mgd; |
870 | 889 | struct ieee80211_if_ibss ibss; |
871 | 890 | struct ieee80211_if_mesh mesh; |
891 | + struct ieee80211_if_ocb ocb; | |
872 | 892 | u32 mntr_flags; |
873 | 893 | } u; |
874 | 894 | |
... | ... | @@ -1504,6 +1524,15 @@ |
1504 | 1524 | struct cfg80211_csa_settings *csa_settings); |
1505 | 1525 | int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata); |
1506 | 1526 | void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata); |
1527 | + | |
1528 | +/* OCB code */ | |
1529 | +void ieee80211_ocb_work(struct ieee80211_sub_if_data *sdata); | |
1530 | +void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |
1531 | + const u8 *bssid, const u8 *addr, u32 supp_rates); | |
1532 | +void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata); | |
1533 | +int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata, | |
1534 | + struct ocb_setup *setup); | |
1535 | +int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata); | |
1507 | 1536 | |
1508 | 1537 | /* mesh code */ |
1509 | 1538 | void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata); |
net/mac80211/iface.c
... | ... | @@ -259,6 +259,15 @@ |
259 | 259 | list_for_each_entry(nsdata, &local->interfaces, list) { |
260 | 260 | if (nsdata != sdata && ieee80211_sdata_running(nsdata)) { |
261 | 261 | /* |
262 | + * Only OCB and monitor mode may coexist | |
263 | + */ | |
264 | + if ((sdata->vif.type == NL80211_IFTYPE_OCB && | |
265 | + nsdata->vif.type != NL80211_IFTYPE_MONITOR) || | |
266 | + (sdata->vif.type != NL80211_IFTYPE_MONITOR && | |
267 | + nsdata->vif.type == NL80211_IFTYPE_OCB)) | |
268 | + return -EBUSY; | |
269 | + | |
270 | + /* | |
262 | 271 | * Allow only a single IBSS interface to be up at any |
263 | 272 | * time. This is restricted because beacon distribution |
264 | 273 | * cannot work properly if both are in the same IBSS. |
... | ... | @@ -1283,6 +1292,9 @@ |
1283 | 1292 | break; |
1284 | 1293 | ieee80211_mesh_work(sdata); |
1285 | 1294 | break; |
1295 | + case NL80211_IFTYPE_OCB: | |
1296 | + ieee80211_ocb_work(sdata); | |
1297 | + break; | |
1286 | 1298 | default: |
1287 | 1299 | break; |
1288 | 1300 | } |
... | ... | @@ -1302,6 +1314,9 @@ |
1302 | 1314 | static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, |
1303 | 1315 | enum nl80211_iftype type) |
1304 | 1316 | { |
1317 | + static const u8 bssid_wildcard[ETH_ALEN] = {0xff, 0xff, 0xff, | |
1318 | + 0xff, 0xff, 0xff}; | |
1319 | + | |
1305 | 1320 | /* clear type-dependent union */ |
1306 | 1321 | memset(&sdata->u, 0, sizeof(sdata->u)); |
1307 | 1322 | |
... | ... | @@ -1354,7 +1369,8 @@ |
1354 | 1369 | ieee80211_sta_setup_sdata(sdata); |
1355 | 1370 | break; |
1356 | 1371 | case NL80211_IFTYPE_OCB: |
1357 | - /* to be implemented in the future */ | |
1372 | + sdata->vif.bss_conf.bssid = bssid_wildcard; | |
1373 | + ieee80211_ocb_setup_sdata(sdata); | |
1358 | 1374 | break; |
1359 | 1375 | case NL80211_IFTYPE_ADHOC: |
1360 | 1376 | sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; |
... | ... | @@ -1403,6 +1419,7 @@ |
1403 | 1419 | case NL80211_IFTYPE_AP: |
1404 | 1420 | case NL80211_IFTYPE_STATION: |
1405 | 1421 | case NL80211_IFTYPE_ADHOC: |
1422 | + case NL80211_IFTYPE_OCB: | |
1406 | 1423 | /* |
1407 | 1424 | * Could maybe also all others here? |
1408 | 1425 | * Just not sure how that interacts |
... | ... | @@ -1418,6 +1435,7 @@ |
1418 | 1435 | case NL80211_IFTYPE_AP: |
1419 | 1436 | case NL80211_IFTYPE_STATION: |
1420 | 1437 | case NL80211_IFTYPE_ADHOC: |
1438 | + case NL80211_IFTYPE_OCB: | |
1421 | 1439 | /* |
1422 | 1440 | * Could probably support everything |
1423 | 1441 | * but WDS here (WDS do_open can fail |
net/mac80211/ocb.c
1 | +/* | |
2 | + * OCB mode implementation | |
3 | + * | |
4 | + * Copyright: (c) 2014 Czech Technical University in Prague | |
5 | + * (c) 2014 Volkswagen Group Research | |
6 | + * Author: Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz> | |
7 | + * Funded by: Volkswagen Group Research | |
8 | + * | |
9 | + * This program is free software; you can redistribute it and/or modify | |
10 | + * it under the terms of the GNU General Public License version 2 as | |
11 | + * published by the Free Software Foundation. | |
12 | + */ | |
13 | + | |
14 | +#include <linux/delay.h> | |
15 | +#include <linux/if_ether.h> | |
16 | +#include <linux/skbuff.h> | |
17 | +#include <linux/if_arp.h> | |
18 | +#include <linux/etherdevice.h> | |
19 | +#include <linux/rtnetlink.h> | |
20 | +#include <net/mac80211.h> | |
21 | +#include <asm/unaligned.h> | |
22 | + | |
23 | +#include "ieee80211_i.h" | |
24 | +#include "driver-ops.h" | |
25 | +#include "rate.h" | |
26 | + | |
27 | +#define IEEE80211_OCB_HOUSEKEEPING_INTERVAL (60 * HZ) | |
28 | +#define IEEE80211_OCB_PEER_INACTIVITY_LIMIT (240 * HZ) | |
29 | +#define IEEE80211_OCB_MAX_STA_ENTRIES 128 | |
30 | + | |
31 | +/** | |
32 | + * enum ocb_deferred_task_flags - mac80211 OCB deferred tasks | |
33 | + * @OCB_WORK_HOUSEKEEPING: run the periodic OCB housekeeping tasks | |
34 | + * | |
35 | + * These flags are used in @wrkq_flags field of &struct ieee80211_if_ocb | |
36 | + */ | |
37 | +enum ocb_deferred_task_flags { | |
38 | + OCB_WORK_HOUSEKEEPING, | |
39 | +}; | |
40 | + | |
41 | +void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata, | |
42 | + const u8 *bssid, const u8 *addr, | |
43 | + u32 supp_rates) | |
44 | +{ | |
45 | + struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | |
46 | + struct ieee80211_local *local = sdata->local; | |
47 | + struct ieee80211_chanctx_conf *chanctx_conf; | |
48 | + struct ieee80211_supported_band *sband; | |
49 | + enum nl80211_bss_scan_width scan_width; | |
50 | + struct sta_info *sta; | |
51 | + int band; | |
52 | + | |
53 | + /* XXX: Consider removing the least recently used entry and | |
54 | + * allow new one to be added. | |
55 | + */ | |
56 | + if (local->num_sta >= IEEE80211_OCB_MAX_STA_ENTRIES) { | |
57 | + net_info_ratelimited("%s: No room for a new OCB STA entry %pM\n", | |
58 | + sdata->name, addr); | |
59 | + return; | |
60 | + } | |
61 | + | |
62 | + ocb_dbg(sdata, "Adding new OCB station %pM\n", addr); | |
63 | + | |
64 | + rcu_read_lock(); | |
65 | + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | |
66 | + if (WARN_ON_ONCE(!chanctx_conf)) { | |
67 | + rcu_read_unlock(); | |
68 | + return; | |
69 | + } | |
70 | + band = chanctx_conf->def.chan->band; | |
71 | + scan_width = cfg80211_chandef_to_scan_width(&chanctx_conf->def); | |
72 | + rcu_read_unlock(); | |
73 | + | |
74 | + sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); | |
75 | + if (!sta) | |
76 | + return; | |
77 | + | |
78 | + sta->last_rx = jiffies; | |
79 | + | |
80 | + /* Add only mandatory rates for now */ | |
81 | + sband = local->hw.wiphy->bands[band]; | |
82 | + sta->sta.supp_rates[band] = | |
83 | + ieee80211_mandatory_rates(sband, scan_width); | |
84 | + | |
85 | + spin_lock(&ifocb->incomplete_lock); | |
86 | + list_add(&sta->list, &ifocb->incomplete_stations); | |
87 | + spin_unlock(&ifocb->incomplete_lock); | |
88 | + ieee80211_queue_work(&local->hw, &sdata->work); | |
89 | +} | |
90 | + | |
91 | +static struct sta_info *ieee80211_ocb_finish_sta(struct sta_info *sta) | |
92 | + __acquires(RCU) | |
93 | +{ | |
94 | + struct ieee80211_sub_if_data *sdata = sta->sdata; | |
95 | + u8 addr[ETH_ALEN]; | |
96 | + | |
97 | + memcpy(addr, sta->sta.addr, ETH_ALEN); | |
98 | + | |
99 | + ocb_dbg(sdata, "Adding new IBSS station %pM (dev=%s)\n", | |
100 | + addr, sdata->name); | |
101 | + | |
102 | + sta_info_move_state(sta, IEEE80211_STA_AUTH); | |
103 | + sta_info_move_state(sta, IEEE80211_STA_ASSOC); | |
104 | + sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); | |
105 | + | |
106 | + rate_control_rate_init(sta); | |
107 | + | |
108 | + /* If it fails, maybe we raced another insertion? */ | |
109 | + if (sta_info_insert_rcu(sta)) | |
110 | + return sta_info_get(sdata, addr); | |
111 | + return sta; | |
112 | +} | |
113 | + | |
114 | +static void ieee80211_ocb_housekeeping(struct ieee80211_sub_if_data *sdata) | |
115 | +{ | |
116 | + struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | |
117 | + | |
118 | + ocb_dbg(sdata, "Running ocb housekeeping\n"); | |
119 | + | |
120 | + ieee80211_sta_expire(sdata, IEEE80211_OCB_PEER_INACTIVITY_LIMIT); | |
121 | + | |
122 | + mod_timer(&ifocb->housekeeping_timer, | |
123 | + round_jiffies(jiffies + IEEE80211_OCB_HOUSEKEEPING_INTERVAL)); | |
124 | +} | |
125 | + | |
126 | +void ieee80211_ocb_work(struct ieee80211_sub_if_data *sdata) | |
127 | +{ | |
128 | + struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | |
129 | + struct sta_info *sta; | |
130 | + | |
131 | + if (ifocb->joined != true) | |
132 | + return; | |
133 | + | |
134 | + sdata_lock(sdata); | |
135 | + | |
136 | + spin_lock_bh(&ifocb->incomplete_lock); | |
137 | + while (!list_empty(&ifocb->incomplete_stations)) { | |
138 | + sta = list_first_entry(&ifocb->incomplete_stations, | |
139 | + struct sta_info, list); | |
140 | + list_del(&sta->list); | |
141 | + spin_unlock_bh(&ifocb->incomplete_lock); | |
142 | + | |
143 | + ieee80211_ocb_finish_sta(sta); | |
144 | + rcu_read_unlock(); | |
145 | + spin_lock_bh(&ifocb->incomplete_lock); | |
146 | + } | |
147 | + spin_unlock_bh(&ifocb->incomplete_lock); | |
148 | + | |
149 | + if (test_and_clear_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags)) | |
150 | + ieee80211_ocb_housekeeping(sdata); | |
151 | + | |
152 | + sdata_unlock(sdata); | |
153 | +} | |
154 | + | |
155 | +static void ieee80211_ocb_housekeeping_timer(unsigned long data) | |
156 | +{ | |
157 | + struct ieee80211_sub_if_data *sdata = (void *)data; | |
158 | + struct ieee80211_local *local = sdata->local; | |
159 | + struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | |
160 | + | |
161 | + set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags); | |
162 | + | |
163 | + ieee80211_queue_work(&local->hw, &sdata->work); | |
164 | +} | |
165 | + | |
166 | +void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata) | |
167 | +{ | |
168 | + struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | |
169 | + | |
170 | + setup_timer(&ifocb->housekeeping_timer, | |
171 | + ieee80211_ocb_housekeeping_timer, | |
172 | + (unsigned long)sdata); | |
173 | + INIT_LIST_HEAD(&ifocb->incomplete_stations); | |
174 | + spin_lock_init(&ifocb->incomplete_lock); | |
175 | +} | |
176 | + | |
177 | +int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata, | |
178 | + struct ocb_setup *setup) | |
179 | +{ | |
180 | + struct ieee80211_local *local = sdata->local; | |
181 | + struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | |
182 | + u32 changed = BSS_CHANGED_OCB; | |
183 | + int err; | |
184 | + | |
185 | + if (ifocb->joined == true) | |
186 | + return -EINVAL; | |
187 | + | |
188 | + sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE; | |
189 | + sdata->smps_mode = IEEE80211_SMPS_OFF; | |
190 | + sdata->needed_rx_chains = sdata->local->rx_chains; | |
191 | + | |
192 | + mutex_lock(&sdata->local->mtx); | |
193 | + err = ieee80211_vif_use_channel(sdata, &setup->chandef, | |
194 | + IEEE80211_CHANCTX_SHARED); | |
195 | + mutex_unlock(&sdata->local->mtx); | |
196 | + if (err) | |
197 | + return err; | |
198 | + | |
199 | + ieee80211_bss_info_change_notify(sdata, changed); | |
200 | + | |
201 | + ifocb->joined = true; | |
202 | + | |
203 | + set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags); | |
204 | + ieee80211_queue_work(&local->hw, &sdata->work); | |
205 | + | |
206 | + netif_carrier_on(sdata->dev); | |
207 | + return 0; | |
208 | +} | |
209 | + | |
210 | +int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata) | |
211 | +{ | |
212 | + struct ieee80211_if_ocb *ifocb = &sdata->u.ocb; | |
213 | + struct ieee80211_local *local = sdata->local; | |
214 | + struct sta_info *sta; | |
215 | + | |
216 | + ifocb->joined = false; | |
217 | + sta_info_flush(sdata); | |
218 | + | |
219 | + spin_lock_bh(&ifocb->incomplete_lock); | |
220 | + while (!list_empty(&ifocb->incomplete_stations)) { | |
221 | + sta = list_first_entry(&ifocb->incomplete_stations, | |
222 | + struct sta_info, list); | |
223 | + list_del(&sta->list); | |
224 | + spin_unlock_bh(&ifocb->incomplete_lock); | |
225 | + | |
226 | + sta_info_free(local, sta); | |
227 | + spin_lock_bh(&ifocb->incomplete_lock); | |
228 | + } | |
229 | + spin_unlock_bh(&ifocb->incomplete_lock); | |
230 | + | |
231 | + netif_carrier_off(sdata->dev); | |
232 | + clear_bit(SDATA_STATE_OFFCHANNEL, &sdata->state); | |
233 | + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_OCB); | |
234 | + | |
235 | + mutex_lock(&sdata->local->mtx); | |
236 | + ieee80211_vif_release_channel(sdata); | |
237 | + mutex_unlock(&sdata->local->mtx); | |
238 | + | |
239 | + skb_queue_purge(&sdata->skb_queue); | |
240 | + | |
241 | + del_timer_sync(&sdata->u.ocb.housekeeping_timer); | |
242 | + /* If the timer fired while we waited for it, it will have | |
243 | + * requeued the work. Now the work will be running again | |
244 | + * but will not rearm the timer again because it checks | |
245 | + * whether we are connected to the network or not -- at this | |
246 | + * point we shouldn't be anymore. | |
247 | + */ | |
248 | + | |
249 | + return 0; | |
250 | +} |
net/mac80211/rx.c
... | ... | @@ -1032,6 +1032,7 @@ |
1032 | 1032 | ieee80211_is_pspoll(hdr->frame_control)) && |
1033 | 1033 | rx->sdata->vif.type != NL80211_IFTYPE_ADHOC && |
1034 | 1034 | rx->sdata->vif.type != NL80211_IFTYPE_WDS && |
1035 | + rx->sdata->vif.type != NL80211_IFTYPE_OCB && | |
1035 | 1036 | (!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_ASSOC)))) { |
1036 | 1037 | /* |
1037 | 1038 | * accept port control frames from the AP even when it's not |
... | ... | @@ -1272,6 +1273,12 @@ |
1272 | 1273 | sta->last_rx_rate_vht_nss = status->vht_nss; |
1273 | 1274 | } |
1274 | 1275 | } |
1276 | + } else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) { | |
1277 | + u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, | |
1278 | + NL80211_IFTYPE_OCB); | |
1279 | + /* OCB uses wild-card BSSID */ | |
1280 | + if (is_broadcast_ether_addr(bssid)) | |
1281 | + sta->last_rx = jiffies; | |
1275 | 1282 | } else if (!is_multicast_ether_addr(hdr->addr1)) { |
1276 | 1283 | /* |
1277 | 1284 | * Mesh beacons will update last_rx when if they are found to |
... | ... | @@ -2820,6 +2827,7 @@ |
2820 | 2827 | |
2821 | 2828 | if (!ieee80211_vif_is_mesh(&sdata->vif) && |
2822 | 2829 | sdata->vif.type != NL80211_IFTYPE_ADHOC && |
2830 | + sdata->vif.type != NL80211_IFTYPE_OCB && | |
2823 | 2831 | sdata->vif.type != NL80211_IFTYPE_STATION) |
2824 | 2832 | return RX_DROP_MONITOR; |
2825 | 2833 | |
... | ... | @@ -3128,6 +3136,33 @@ |
3128 | 3136 | rate_idx = status->rate_idx; |
3129 | 3137 | ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2, |
3130 | 3138 | BIT(rate_idx)); |
3139 | + } | |
3140 | + break; | |
3141 | + case NL80211_IFTYPE_OCB: | |
3142 | + if (!bssid) | |
3143 | + return false; | |
3144 | + if (ieee80211_is_beacon(hdr->frame_control)) { | |
3145 | + return false; | |
3146 | + } else if (!is_broadcast_ether_addr(bssid)) { | |
3147 | + ocb_dbg(sdata, "BSSID mismatch in OCB mode!\n"); | |
3148 | + return false; | |
3149 | + } else if (!multicast && | |
3150 | + !ether_addr_equal(sdata->dev->dev_addr, | |
3151 | + hdr->addr1)) { | |
3152 | + /* if we are in promisc mode we also accept | |
3153 | + * packets not destined for us | |
3154 | + */ | |
3155 | + if (!(sdata->dev->flags & IFF_PROMISC)) | |
3156 | + return false; | |
3157 | + rx->flags &= ~IEEE80211_RX_RA_MATCH; | |
3158 | + } else if (!rx->sta) { | |
3159 | + int rate_idx; | |
3160 | + if (status->flag & RX_FLAG_HT) | |
3161 | + rate_idx = 0; /* TODO: HT rates */ | |
3162 | + else | |
3163 | + rate_idx = status->rate_idx; | |
3164 | + ieee80211_ocb_rx_no_sta(sdata, bssid, hdr->addr2, | |
3165 | + BIT(rate_idx)); | |
3131 | 3166 | } |
3132 | 3167 | break; |
3133 | 3168 | case NL80211_IFTYPE_MESH_POINT: |
net/mac80211/tx.c
... | ... | @@ -296,6 +296,9 @@ |
296 | 296 | */ |
297 | 297 | return TX_DROP; |
298 | 298 | |
299 | + if (tx->sdata->vif.type == NL80211_IFTYPE_OCB) | |
300 | + return TX_CONTINUE; | |
301 | + | |
299 | 302 | if (tx->sdata->vif.type == NL80211_IFTYPE_WDS) |
300 | 303 | return TX_CONTINUE; |
301 | 304 | |
... | ... | @@ -2013,6 +2016,17 @@ |
2013 | 2016 | goto fail_rcu; |
2014 | 2017 | band = chanctx_conf->def.chan->band; |
2015 | 2018 | break; |
2019 | + case NL80211_IFTYPE_OCB: | |
2020 | + /* DA SA BSSID */ | |
2021 | + memcpy(hdr.addr1, skb->data, ETH_ALEN); | |
2022 | + memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); | |
2023 | + eth_broadcast_addr(hdr.addr3); | |
2024 | + hdrlen = 24; | |
2025 | + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); | |
2026 | + if (!chanctx_conf) | |
2027 | + goto fail_rcu; | |
2028 | + band = chanctx_conf->def.chan->band; | |
2029 | + break; | |
2016 | 2030 | case NL80211_IFTYPE_ADHOC: |
2017 | 2031 | /* DA SA BSSID */ |
2018 | 2032 | memcpy(hdr.addr1, skb->data, ETH_ALEN); |
... | ... | @@ -2057,6 +2071,7 @@ |
2057 | 2071 | * EAPOL frames from the local station. |
2058 | 2072 | */ |
2059 | 2073 | if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) && |
2074 | + (sdata->vif.type != NL80211_IFTYPE_OCB) && | |
2060 | 2075 | !multicast && !authorized && |
2061 | 2076 | (cpu_to_be16(ethertype) != sdata->control_port_protocol || |
2062 | 2077 | !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) { |
net/mac80211/util.c
... | ... | @@ -1101,6 +1101,7 @@ |
1101 | 1101 | struct ieee80211_chanctx_conf *chanctx_conf; |
1102 | 1102 | int ac; |
1103 | 1103 | bool use_11b, enable_qos; |
1104 | + bool is_ocb; /* Use another EDCA parameters if dot11OCBActivated=true */ | |
1104 | 1105 | int aCWmin, aCWmax; |
1105 | 1106 | |
1106 | 1107 | if (!local->ops->conf_tx) |
... | ... | @@ -1125,6 +1126,8 @@ |
1125 | 1126 | */ |
1126 | 1127 | enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION); |
1127 | 1128 | |
1129 | + is_ocb = (sdata->vif.type == NL80211_IFTYPE_OCB); | |
1130 | + | |
1128 | 1131 | /* Set defaults according to 802.11-2007 Table 7-37 */ |
1129 | 1132 | aCWmax = 1023; |
1130 | 1133 | if (use_11b) |
... | ... | @@ -1146,7 +1149,10 @@ |
1146 | 1149 | qparam.cw_max = aCWmax; |
1147 | 1150 | qparam.cw_min = aCWmin; |
1148 | 1151 | qparam.txop = 0; |
1149 | - qparam.aifs = 7; | |
1152 | + if (is_ocb) | |
1153 | + qparam.aifs = 9; | |
1154 | + else | |
1155 | + qparam.aifs = 7; | |
1150 | 1156 | break; |
1151 | 1157 | /* never happens but let's not leave undefined */ |
1152 | 1158 | default: |
1153 | 1159 | |
1154 | 1160 | |
1155 | 1161 | |
... | ... | @@ -1154,21 +1160,32 @@ |
1154 | 1160 | qparam.cw_max = aCWmax; |
1155 | 1161 | qparam.cw_min = aCWmin; |
1156 | 1162 | qparam.txop = 0; |
1157 | - qparam.aifs = 3; | |
1163 | + if (is_ocb) | |
1164 | + qparam.aifs = 6; | |
1165 | + else | |
1166 | + qparam.aifs = 3; | |
1158 | 1167 | break; |
1159 | 1168 | case IEEE80211_AC_VI: |
1160 | 1169 | qparam.cw_max = aCWmin; |
1161 | 1170 | qparam.cw_min = (aCWmin + 1) / 2 - 1; |
1162 | - if (use_11b) | |
1171 | + if (is_ocb) | |
1172 | + qparam.txop = 0; | |
1173 | + else if (use_11b) | |
1163 | 1174 | qparam.txop = 6016/32; |
1164 | 1175 | else |
1165 | 1176 | qparam.txop = 3008/32; |
1166 | - qparam.aifs = 2; | |
1177 | + | |
1178 | + if (is_ocb) | |
1179 | + qparam.aifs = 3; | |
1180 | + else | |
1181 | + qparam.aifs = 2; | |
1167 | 1182 | break; |
1168 | 1183 | case IEEE80211_AC_VO: |
1169 | 1184 | qparam.cw_max = (aCWmin + 1) / 2 - 1; |
1170 | 1185 | qparam.cw_min = (aCWmin + 1) / 4 - 1; |
1171 | - if (use_11b) | |
1186 | + if (is_ocb) | |
1187 | + qparam.txop = 0; | |
1188 | + else if (use_11b) | |
1172 | 1189 | qparam.txop = 3264/32; |
1173 | 1190 | else |
1174 | 1191 | qparam.txop = 1504/32; |
... | ... | @@ -1842,7 +1859,8 @@ |
1842 | 1859 | sdata_unlock(sdata); |
1843 | 1860 | break; |
1844 | 1861 | case NL80211_IFTYPE_OCB: |
1845 | - /* to be implemented in the future */ | |
1862 | + changed |= BSS_CHANGED_OCB; | |
1863 | + ieee80211_bss_info_change_notify(sdata, changed); | |
1846 | 1864 | break; |
1847 | 1865 | case NL80211_IFTYPE_ADHOC: |
1848 | 1866 | changed |= BSS_CHANGED_IBSS; |
net/mac80211/wme.c