Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Rostislav Lisovy and committed by
Johannes Berg
239281f8 6e0bd6c3

+417 -9
+2
include/net/mac80211.h
··· 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, ··· 288 287 BSS_CHANGED_P2P_PS = 1<<19, 289 288 BSS_CHANGED_BEACON_INFO = 1<<20, 290 289 BSS_CHANGED_BANDWIDTH = 1<<21, 290 + BSS_CHANGED_OCB = 1<<22, 291 291 292 292 /* when adding here, make sure to change ieee80211_reconfig */ 293 293 };
+11
net/mac80211/Kconfig
··· 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
+2 -1
net/mac80211/Makefile
··· 27 27 event.o \ 28 28 chan.o \ 29 29 trace.o mlme.o \ 30 - tdls.o 30 + tdls.o \ 31 + ocb.o 31 32 32 33 mac80211-$(CONFIG_MAC80211_LEDS) += led.o 33 34 mac80211-$(CONFIG_MAC80211_DEBUGFS) += \
+13
net/mac80211/cfg.c
··· 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 { ··· 3704 3693 .join_mesh = ieee80211_join_mesh, 3705 3694 .leave_mesh = ieee80211_leave_mesh, 3706 3695 #endif 3696 + .join_ocb = ieee80211_join_ocb, 3697 + .leave_ocb = ieee80211_leave_ocb, 3707 3698 .change_bss = ieee80211_change_bss, 3708 3699 .set_txq_params = ieee80211_set_txq_params, 3709 3700 .set_monitor_channel = ieee80211_set_monitor_channel,
+1
net/mac80211/chan.c
··· 675 675 case NL80211_IFTYPE_ADHOC: 676 676 case NL80211_IFTYPE_WDS: 677 677 case NL80211_IFTYPE_MESH_POINT: 678 + case NL80211_IFTYPE_OCB: 678 679 break; 679 680 default: 680 681 WARN_ON_ONCE(1);
+10
net/mac80211/debug.h
··· 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 ··· 135 129 136 130 #define ht_dbg_ratelimited(sdata, fmt, ...) \ 137 131 _sdata_dbg(MAC80211_HT_DEBUG && net_ratelimit(), \ 132 + sdata, fmt, ##__VA_ARGS__) 133 + 134 + #define ocb_dbg(sdata, fmt, ...) \ 135 + _sdata_dbg(MAC80211_OCB_DEBUG, \ 138 136 sdata, fmt, ##__VA_ARGS__) 139 137 140 138 #define ibss_dbg(sdata, fmt, ...) \
+2 -1
net/mac80211/driver-ops.h
··· 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 ||
+29
net/mac80211/ieee80211_i.h
··· 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 ··· 888 869 struct ieee80211_if_managed mgd; 889 870 struct ieee80211_if_ibss ibss; 890 871 struct ieee80211_if_mesh mesh; 872 + struct ieee80211_if_ocb ocb; 891 873 u32 mntr_flags; 892 874 } u; 893 875 ··· 1524 1504 struct cfg80211_csa_settings *csa_settings); 1525 1505 int ieee80211_ibss_finish_csa(struct ieee80211_sub_if_data *sdata); 1526 1506 void ieee80211_ibss_stop(struct ieee80211_sub_if_data *sdata); 1507 + 1508 + /* OCB code */ 1509 + void ieee80211_ocb_work(struct ieee80211_sub_if_data *sdata); 1510 + void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata, 1511 + const u8 *bssid, const u8 *addr, u32 supp_rates); 1512 + void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata); 1513 + int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata, 1514 + struct ocb_setup *setup); 1515 + int ieee80211_ocb_leave(struct ieee80211_sub_if_data *sdata); 1527 1516 1528 1517 /* mesh code */ 1529 1518 void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata);
+19 -1
net/mac80211/iface.c
··· 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. ··· 1292 1283 break; 1293 1284 ieee80211_mesh_work(sdata); 1294 1285 break; 1286 + case NL80211_IFTYPE_OCB: 1287 + ieee80211_ocb_work(sdata); 1288 + break; 1295 1289 default: 1296 1290 break; 1297 1291 } ··· 1314 1302 static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata, 1315 1303 enum nl80211_iftype type) 1316 1304 { 1305 + static const u8 bssid_wildcard[ETH_ALEN] = {0xff, 0xff, 0xff, 1306 + 0xff, 0xff, 0xff}; 1307 + 1317 1308 /* clear type-dependent union */ 1318 1309 memset(&sdata->u, 0, sizeof(sdata->u)); 1319 1310 ··· 1369 1354 ieee80211_sta_setup_sdata(sdata); 1370 1355 break; 1371 1356 case NL80211_IFTYPE_OCB: 1372 - /* to be implemented in the future */ 1357 + sdata->vif.bss_conf.bssid = bssid_wildcard; 1358 + ieee80211_ocb_setup_sdata(sdata); 1373 1359 break; 1374 1360 case NL80211_IFTYPE_ADHOC: 1375 1361 sdata->vif.bss_conf.bssid = sdata->u.ibss.bssid; ··· 1419 1403 case NL80211_IFTYPE_AP: 1420 1404 case NL80211_IFTYPE_STATION: 1421 1405 case NL80211_IFTYPE_ADHOC: 1406 + case NL80211_IFTYPE_OCB: 1422 1407 /* 1423 1408 * Could maybe also all others here? 1424 1409 * Just not sure how that interacts ··· 1435 1418 case NL80211_IFTYPE_AP: 1436 1419 case NL80211_IFTYPE_STATION: 1437 1420 case NL80211_IFTYPE_ADHOC: 1421 + case NL80211_IFTYPE_OCB: 1438 1422 /* 1439 1423 * Could probably support everything 1440 1424 * but WDS here (WDS do_open can fail
+250
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 + }
+35
net/mac80211/rx.c
··· 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 ··· 1273 1272 sta->last_rx_rate_vht_nss = status->vht_nss; 1274 1273 } 1275 1274 } 1275 + } else if (rx->sdata->vif.type == NL80211_IFTYPE_OCB) { 1276 + u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len, 1277 + NL80211_IFTYPE_OCB); 1278 + /* OCB uses wild-card BSSID */ 1279 + if (is_broadcast_ether_addr(bssid)) 1280 + sta->last_rx = jiffies; 1276 1281 } else if (!is_multicast_ether_addr(hdr->addr1)) { 1277 1282 /* 1278 1283 * Mesh beacons will update last_rx when if they are found to ··· 2827 2820 2828 2821 if (!ieee80211_vif_is_mesh(&sdata->vif) && 2829 2822 sdata->vif.type != NL80211_IFTYPE_ADHOC && 2823 + sdata->vif.type != NL80211_IFTYPE_OCB && 2830 2824 sdata->vif.type != NL80211_IFTYPE_STATION) 2831 2825 return RX_DROP_MONITOR; 2832 2826 ··· 3136 3128 rate_idx = status->rate_idx; 3137 3129 ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2, 3138 3130 BIT(rate_idx)); 3131 + } 3132 + break; 3133 + case NL80211_IFTYPE_OCB: 3134 + if (!bssid) 3135 + return false; 3136 + if (ieee80211_is_beacon(hdr->frame_control)) { 3137 + return false; 3138 + } else if (!is_broadcast_ether_addr(bssid)) { 3139 + ocb_dbg(sdata, "BSSID mismatch in OCB mode!\n"); 3140 + return false; 3141 + } else if (!multicast && 3142 + !ether_addr_equal(sdata->dev->dev_addr, 3143 + hdr->addr1)) { 3144 + /* if we are in promisc mode we also accept 3145 + * packets not destined for us 3146 + */ 3147 + if (!(sdata->dev->flags & IFF_PROMISC)) 3148 + return false; 3149 + rx->flags &= ~IEEE80211_RX_RA_MATCH; 3150 + } else if (!rx->sta) { 3151 + int rate_idx; 3152 + if (status->flag & RX_FLAG_HT) 3153 + rate_idx = 0; /* TODO: HT rates */ 3154 + else 3155 + rate_idx = status->rate_idx; 3156 + ieee80211_ocb_rx_no_sta(sdata, bssid, hdr->addr2, 3157 + BIT(rate_idx)); 3139 3158 } 3140 3159 break; 3141 3160 case NL80211_IFTYPE_MESH_POINT:
+15
net/mac80211/tx.c
··· 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 ··· 2016 2013 goto fail_rcu; 2017 2014 band = chanctx_conf->def.chan->band; 2018 2015 break; 2016 + case NL80211_IFTYPE_OCB: 2017 + /* DA SA BSSID */ 2018 + memcpy(hdr.addr1, skb->data, ETH_ALEN); 2019 + memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN); 2020 + eth_broadcast_addr(hdr.addr3); 2021 + hdrlen = 24; 2022 + chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); 2023 + if (!chanctx_conf) 2024 + goto fail_rcu; 2025 + band = chanctx_conf->def.chan->band; 2026 + break; 2019 2027 case NL80211_IFTYPE_ADHOC: 2020 2028 /* DA SA BSSID */ 2021 2029 memcpy(hdr.addr1, skb->data, ETH_ALEN); ··· 2071 2057 * EAPOL frames from the local station. 2072 2058 */ 2073 2059 if (unlikely(!ieee80211_vif_is_mesh(&sdata->vif) && 2060 + (sdata->vif.type != NL80211_IFTYPE_OCB) && 2074 2061 !multicast && !authorized && 2075 2062 (cpu_to_be16(ethertype) != sdata->control_port_protocol || 2076 2063 !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) {
+24 -6
net/mac80211/util.c
··· 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) ··· 1126 1125 */ 1127 1126 enable_qos = (sdata->vif.type != NL80211_IFTYPE_STATION); 1128 1127 1128 + is_ocb = (sdata->vif.type == NL80211_IFTYPE_OCB); 1129 + 1129 1130 /* Set defaults according to 802.11-2007 Table 7-37 */ 1130 1131 aCWmax = 1023; 1131 1132 if (use_11b) ··· 1149 1146 qparam.cw_max = aCWmax; 1150 1147 qparam.cw_min = aCWmin; 1151 1148 qparam.txop = 0; 1152 - qparam.aifs = 7; 1149 + if (is_ocb) 1150 + qparam.aifs = 9; 1151 + else 1152 + qparam.aifs = 7; 1153 1153 break; 1154 1154 /* never happens but let's not leave undefined */ 1155 1155 default: ··· 1160 1154 qparam.cw_max = aCWmax; 1161 1155 qparam.cw_min = aCWmin; 1162 1156 qparam.txop = 0; 1163 - qparam.aifs = 3; 1157 + if (is_ocb) 1158 + qparam.aifs = 6; 1159 + else 1160 + qparam.aifs = 3; 1164 1161 break; 1165 1162 case IEEE80211_AC_VI: 1166 1163 qparam.cw_max = aCWmin; 1167 1164 qparam.cw_min = (aCWmin + 1) / 2 - 1; 1168 - if (use_11b) 1165 + if (is_ocb) 1166 + qparam.txop = 0; 1167 + else if (use_11b) 1169 1168 qparam.txop = 6016/32; 1170 1169 else 1171 1170 qparam.txop = 3008/32; 1172 - qparam.aifs = 2; 1171 + 1172 + if (is_ocb) 1173 + qparam.aifs = 3; 1174 + else 1175 + qparam.aifs = 2; 1173 1176 break; 1174 1177 case IEEE80211_AC_VO: 1175 1178 qparam.cw_max = (aCWmin + 1) / 2 - 1; 1176 1179 qparam.cw_min = (aCWmin + 1) / 4 - 1; 1177 - if (use_11b) 1180 + if (is_ocb) 1181 + qparam.txop = 0; 1182 + else if (use_11b) 1178 1183 qparam.txop = 3264/32; 1179 1184 else 1180 1185 qparam.txop = 1504/32; ··· 1859 1842 sdata_unlock(sdata); 1860 1843 break; 1861 1844 case NL80211_IFTYPE_OCB: 1862 - /* to be implemented in the future */ 1845 + changed |= BSS_CHANGED_OCB; 1846 + ieee80211_bss_info_change_notify(sdata, changed); 1863 1847 break; 1864 1848 case NL80211_IFTYPE_ADHOC: 1865 1849 changed |= BSS_CHANGED_IBSS;
+4
net/mac80211/wme.c
··· 148 148 case NL80211_IFTYPE_ADHOC: 149 149 ra = skb->data; 150 150 break; 151 + case NL80211_IFTYPE_OCB: 152 + /* all stations are required to support WME */ 153 + qos = true; 154 + break; 151 155 default: 152 156 break; 153 157 }