mesh_plink.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008, 2009 open80211s Ltd.
00003  * Author:     Luis Carlos Cobo <luisca@cozybit.com>
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License version 2 as
00007  * published by the Free Software Foundation.
00008  */
00009 #include <linux/gfp.h>
00010 #include <linux/kernel.h>
00011 #include <linux/random.h>
00012 #include "ieee80211_i.h"
00013 #include "rate.h"
00014 #include "mesh.h"
00015 
00016 #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
00017 #define mpl_dbg(fmt, args...)   printk(KERN_DEBUG fmt, ##args)
00018 #else
00019 #define mpl_dbg(fmt, args...)   do { (void)(0); } while (0)
00020 #endif
00021 
00022 #define PLINK_GET_LLID(p) (p + 2)
00023 #define PLINK_GET_PLID(p) (p + 4)
00024 
00025 #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
00026                                 jiffies + HZ * t / 1000))
00027 
00028 #define dot11MeshMaxRetries(s) (s->u.mesh.mshcfg.dot11MeshMaxRetries)
00029 #define dot11MeshRetryTimeout(s) (s->u.mesh.mshcfg.dot11MeshRetryTimeout)
00030 #define dot11MeshConfirmTimeout(s) (s->u.mesh.mshcfg.dot11MeshConfirmTimeout)
00031 #define dot11MeshHoldingTimeout(s) (s->u.mesh.mshcfg.dot11MeshHoldingTimeout)
00032 #define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks)
00033 
00034 /* We only need a valid sta if user configured a minimum rssi_threshold. */
00035 #define rssi_threshold_check(sta, sdata) \
00036                 (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\
00037                 (sta && (s8) -ewma_read(&sta->avg_signal) > \
00038                 sdata->u.mesh.mshcfg.rssi_threshold))
00039 
00040 enum plink_event {
00041         PLINK_UNDEFINED,
00042         OPN_ACPT,
00043         OPN_RJCT,
00044         OPN_IGNR,
00045         CNF_ACPT,
00046         CNF_RJCT,
00047         CNF_IGNR,
00048         CLS_ACPT,
00049         CLS_IGNR
00050 };
00051 
00052 static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
00053                 enum ieee80211_self_protected_actioncode action,
00054                 u8 *da, __le16 llid, __le16 plid, __le16 reason);
00055 
00056 static inline
00057 void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
00058 {
00059         atomic_inc(&sdata->u.mesh.mshstats.estab_plinks);
00060         mesh_accept_plinks_update(sdata);
00061 }
00062 
00063 static inline
00064 void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
00065 {
00066         atomic_dec(&sdata->u.mesh.mshstats.estab_plinks);
00067         mesh_accept_plinks_update(sdata);
00068 }
00069 
00077 static inline void mesh_plink_fsm_restart(struct sta_info *sta)
00078 {
00079         sta->plink_state = NL80211_PLINK_LISTEN;
00080         sta->llid = sta->plid = sta->reason = 0;
00081         sta->plink_retries = 0;
00082 }
00083 
00084 /*
00085  * Allocate mesh sta entry and insert into station table
00086  */
00087 static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
00088                                          u8 *hw_addr)
00089 {
00090         struct sta_info *sta;
00091 
00092         if (sdata->local->num_sta >= MESH_MAX_PLINKS)
00093                 return NULL;
00094 
00095         sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL);
00096         if (!sta)
00097                 return NULL;
00098 
00099         sta_info_pre_move_state(sta, IEEE80211_STA_AUTH);
00100         sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC);
00101         sta_info_pre_move_state(sta, IEEE80211_STA_AUTHORIZED);
00102 
00103         set_sta_flag(sta, WLAN_STA_WME);
00104 
00105         return sta;
00106 }
00107 
00108 /*
00109  * mesh_set_ht_prot_mode - set correct HT protection mode
00110  *
00111  * Section 9.23.3.5 of IEEE 80211-2012 describes the protection rules for HT
00112  * mesh STA in a MBSS. Three HT protection modes are supported for now, non-HT
00113  * mixed mode, 20MHz-protection and no-protection mode. non-HT mixed mode is
00114  * selected if any non-HT peers are present in our MBSS.  20MHz-protection mode
00115  * is selected if all peers in our 20/40MHz MBSS support HT and atleast one
00116  * HT20 peer is present. Otherwise no-protection mode is selected.
00117  */
00118 static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
00119 {
00120         struct ieee80211_local *local = sdata->local;
00121         struct sta_info *sta;
00122         u32 changed = 0;
00123         u16 ht_opmode;
00124         bool non_ht_sta = false, ht20_sta = false;
00125 
00126         if (local->_oper_channel_type == NL80211_CHAN_NO_HT)
00127                 return 0;
00128 
00129         rcu_read_lock();
00130         list_for_each_entry_rcu(sta, &local->sta_list, list) {
00131                 if (sdata != sta->sdata ||
00132                     sta->plink_state != NL80211_PLINK_ESTAB)
00133                         continue;
00134 
00135                 switch (sta->ch_type) {
00136                 case NL80211_CHAN_NO_HT:
00137                         mpl_dbg("mesh_plink %pM: nonHT sta (%pM) is present",
00138                                 sdata->vif.addr, sta->sta.addr);
00139                         non_ht_sta = true;
00140                         goto out;
00141                 case NL80211_CHAN_HT20:
00142                         mpl_dbg("mesh_plink %pM: HT20 sta (%pM) is present",
00143                                 sdata->vif.addr, sta->sta.addr);
00144                         ht20_sta = true;
00145                 default:
00146                         break;
00147                 }
00148         }
00149 out:
00150         rcu_read_unlock();
00151 
00152         if (non_ht_sta)
00153                 ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED;
00154         else if (ht20_sta && local->_oper_channel_type > NL80211_CHAN_HT20)
00155                 ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ;
00156         else
00157                 ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
00158 
00159         if (sdata->vif.bss_conf.ht_operation_mode != ht_opmode) {
00160                 sdata->vif.bss_conf.ht_operation_mode = ht_opmode;
00161                 sdata->u.mesh.mshcfg.ht_opmode = ht_opmode;
00162                 changed = BSS_CHANGED_HT;
00163                 mpl_dbg("mesh_plink %pM: protection mode changed to %d",
00164                         sdata->vif.addr, ht_opmode);
00165         }
00166 
00167         return changed;
00168 }
00169 
00179 static bool __mesh_plink_deactivate(struct sta_info *sta)
00180 {
00181         struct ieee80211_sub_if_data *sdata = sta->sdata;
00182         bool deactivated = false;
00183 
00184         if (sta->plink_state == NL80211_PLINK_ESTAB) {
00185                 mesh_plink_dec_estab_count(sdata);
00186                 deactivated = true;
00187         }
00188         sta->plink_state = NL80211_PLINK_BLOCKED;
00189         mesh_path_flush_by_nexthop(sta);
00190 
00191         return deactivated;
00192 }
00193 
00201 void mesh_plink_deactivate(struct sta_info *sta)
00202 {
00203         struct ieee80211_sub_if_data *sdata = sta->sdata;
00204         bool deactivated;
00205 
00206         spin_lock_bh(&sta->lock);
00207         deactivated = __mesh_plink_deactivate(sta);
00208         sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED);
00209         mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
00210                             sta->sta.addr, sta->llid, sta->plid,
00211                             sta->reason);
00212         spin_unlock_bh(&sta->lock);
00213 
00214         if (deactivated)
00215                 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
00216 }
00217 
00218 static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
00219                 enum ieee80211_self_protected_actioncode action,
00220                 u8 *da, __le16 llid, __le16 plid, __le16 reason) {
00221         struct ieee80211_local *local = sdata->local;
00222         struct sk_buff *skb;
00223         struct ieee80211_mgmt *mgmt;
00224         bool include_plid = false;
00225         u16 peering_proto = 0;
00226         u8 *pos, ie_len = 4;
00227         int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.self_prot) +
00228                       sizeof(mgmt->u.action.u.self_prot);
00229 
00230         skb = dev_alloc_skb(local->tx_headroom +
00231                             hdr_len +
00232                             2 + /* capability info */
00233                             2 + /* AID */
00234                             2 + 8 + /* supported rates */
00235                             2 + (IEEE80211_MAX_SUPP_RATES - 8) +
00236                             2 + sdata->u.mesh.mesh_id_len +
00237                             2 + sizeof(struct ieee80211_meshconf_ie) +
00238                             2 + sizeof(struct ieee80211_ht_cap) +
00239                             2 + sizeof(struct ieee80211_ht_operation) +
00240                             2 + 8 + /* peering IE */
00241                             sdata->u.mesh.ie_len);
00242         if (!skb)
00243                 return -1;
00244         skb_reserve(skb, local->tx_headroom);
00245         mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
00246         memset(mgmt, 0, hdr_len);
00247         mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
00248                                           IEEE80211_STYPE_ACTION);
00249         memcpy(mgmt->da, da, ETH_ALEN);
00250         memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
00251         memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
00252         mgmt->u.action.category = WLAN_CATEGORY_SELF_PROTECTED;
00253         mgmt->u.action.u.self_prot.action_code = action;
00254 
00255         if (action != WLAN_SP_MESH_PEERING_CLOSE) {
00256                 /* capability info */
00257                 pos = skb_put(skb, 2);
00258                 memset(pos, 0, 2);
00259                 if (action == WLAN_SP_MESH_PEERING_CONFIRM) {
00260                         /* AID */
00261                         pos = skb_put(skb, 2);
00262                         memcpy(pos + 2, &plid, 2);
00263                 }
00264                 if (ieee80211_add_srates_ie(&sdata->vif, skb, true) ||
00265                     ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) ||
00266                     mesh_add_rsn_ie(skb, sdata) ||
00267                     mesh_add_meshid_ie(skb, sdata) ||
00268                     mesh_add_meshconf_ie(skb, sdata))
00269                         return -1;
00270         } else {        /* WLAN_SP_MESH_PEERING_CLOSE */
00271                 if (mesh_add_meshid_ie(skb, sdata))
00272                         return -1;
00273         }
00274 
00275         /* Add Mesh Peering Management element */
00276         switch (action) {
00277         case WLAN_SP_MESH_PEERING_OPEN:
00278                 break;
00279         case WLAN_SP_MESH_PEERING_CONFIRM:
00280                 ie_len += 2;
00281                 include_plid = true;
00282                 break;
00283         case WLAN_SP_MESH_PEERING_CLOSE:
00284                 if (plid) {
00285                         ie_len += 2;
00286                         include_plid = true;
00287                 }
00288                 ie_len += 2;    /* reason code */
00289                 break;
00290         default:
00291                 return -EINVAL;
00292         }
00293 
00294         if (WARN_ON(skb_tailroom(skb) < 2 + ie_len))
00295                 return -ENOMEM;
00296 
00297         pos = skb_put(skb, 2 + ie_len);
00298         *pos++ = WLAN_EID_PEER_MGMT;
00299         *pos++ = ie_len;
00300         memcpy(pos, &peering_proto, 2);
00301         pos += 2;
00302         memcpy(pos, &llid, 2);
00303         pos += 2;
00304         if (include_plid) {
00305                 memcpy(pos, &plid, 2);
00306                 pos += 2;
00307         }
00308         if (action == WLAN_SP_MESH_PEERING_CLOSE) {
00309                 memcpy(pos, &reason, 2);
00310                 pos += 2;
00311         }
00312 
00313         if (action != WLAN_SP_MESH_PEERING_CLOSE) {
00314                 if (mesh_add_ht_cap_ie(skb, sdata) ||
00315                     mesh_add_ht_oper_ie(skb, sdata))
00316                         return -1;
00317         }
00318 
00319         if (mesh_add_vendor_ies(skb, sdata))
00320                 return -1;
00321 
00322         ieee80211_tx_skb(sdata, skb);
00323         return 0;
00324 }
00325 
00326 /* mesh_peer_init - initialize new mesh peer and return resulting sta_info
00327  *
00328  * @sdata: local meshif
00329  * @addr: peer's address
00330  * @elems: IEs from beacon or mesh peering frame
00331  *
00332  * call under RCU
00333  */
00334 static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
00335                                        u8 *addr,
00336                                        struct ieee802_11_elems *elems)
00337 {
00338         struct ieee80211_local *local = sdata->local;
00339         enum ieee80211_band band = local->oper_channel->band;
00340         struct ieee80211_supported_band *sband;
00341         u32 rates, basic_rates = 0;
00342         struct sta_info *sta;
00343         bool insert = false;
00344 
00345         sband = local->hw.wiphy->bands[band];
00346         rates = ieee80211_sta_get_rates(local, elems, band, &basic_rates);
00347 
00348         sta = sta_info_get(sdata, addr);
00349         if (!sta) {
00350                 /* Userspace handles peer allocation when security is enabled */
00351                 if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) {
00352                         cfg80211_notify_new_peer_candidate(sdata->dev, addr,
00353                                                            elems->ie_start,
00354                                                            elems->total_len,
00355                                                            GFP_ATOMIC);
00356                         return NULL;
00357                 }
00358 
00359                 sta = mesh_plink_alloc(sdata, addr);
00360                 if (!sta)
00361                         return NULL;
00362                 insert = true;
00363         }
00364 
00365         spin_lock_bh(&sta->lock);
00366         sta->last_rx = jiffies;
00367         sta->sta.supp_rates[band] = rates;
00368         if (elems->ht_cap_elem &&
00369             sdata->local->_oper_channel_type != NL80211_CHAN_NO_HT)
00370                 ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
00371                                                   elems->ht_cap_elem,
00372                                                   &sta->sta.ht_cap);
00373         else
00374                 memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap));
00375 
00376         if (elems->ht_operation) {
00377                 if (!(elems->ht_operation->ht_param &
00378                       IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
00379                         sta->sta.ht_cap.cap &=
00380                                             ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
00381                 sta->ch_type =
00382                         ieee80211_ht_oper_to_channel_type(elems->ht_operation);
00383         }
00384 
00385         rate_control_rate_init(sta);
00386         spin_unlock_bh(&sta->lock);
00387 
00388         if (insert && sta_info_insert(sta))
00389                 return NULL;
00390 
00391         return sta;
00392 }
00393 
00394 void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
00395                            u8 *hw_addr,
00396                            struct ieee802_11_elems *elems)
00397 {
00398         struct sta_info *sta;
00399 
00400         rcu_read_lock();
00401         sta = mesh_peer_init(sdata, hw_addr, elems);
00402         if (!sta)
00403                 goto out;
00404 
00405         if (mesh_peer_accepts_plinks(elems) &&
00406             sta->plink_state == NL80211_PLINK_LISTEN &&
00407             sdata->u.mesh.accepting_plinks &&
00408             sdata->u.mesh.mshcfg.auto_open_plinks &&
00409             rssi_threshold_check(sta, sdata))
00410                 mesh_plink_open(sta);
00411 
00412 out:
00413         rcu_read_unlock();
00414 }
00415 
00416 static void mesh_plink_timer(unsigned long data)
00417 {
00418         struct sta_info *sta;
00419         __le16 llid, plid, reason;
00420         struct ieee80211_sub_if_data *sdata;
00421 
00422         /*
00423          * This STA is valid because sta_info_destroy() will
00424          * del_timer_sync() this timer after having made sure
00425          * it cannot be readded (by deleting the plink.)
00426          */
00427         sta = (struct sta_info *) data;
00428 
00429         if (sta->sdata->local->quiescing) {
00430                 sta->plink_timer_was_running = true;
00431                 return;
00432         }
00433 
00434         spin_lock_bh(&sta->lock);
00435         if (sta->ignore_plink_timer) {
00436                 sta->ignore_plink_timer = false;
00437                 spin_unlock_bh(&sta->lock);
00438                 return;
00439         }
00440         mpl_dbg("Mesh plink timer for %pM fired on state %d\n",
00441                 sta->sta.addr, sta->plink_state);
00442         reason = 0;
00443         llid = sta->llid;
00444         plid = sta->plid;
00445         sdata = sta->sdata;
00446 
00447         switch (sta->plink_state) {
00448         case NL80211_PLINK_OPN_RCVD:
00449         case NL80211_PLINK_OPN_SNT:
00450                 /* retry timer */
00451                 if (sta->plink_retries < dot11MeshMaxRetries(sdata)) {
00452                         u32 rand;
00453                         mpl_dbg("Mesh plink for %pM (retry, timeout): %d %d\n",
00454                                 sta->sta.addr, sta->plink_retries,
00455                                 sta->plink_timeout);
00456                         get_random_bytes(&rand, sizeof(u32));
00457                         sta->plink_timeout = sta->plink_timeout +
00458                                              rand % sta->plink_timeout;
00459                         ++sta->plink_retries;
00460                         mod_plink_timer(sta, sta->plink_timeout);
00461                         spin_unlock_bh(&sta->lock);
00462                         mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
00463                                             sta->sta.addr, llid, 0, 0);
00464                         break;
00465                 }
00466                 reason = cpu_to_le16(WLAN_REASON_MESH_MAX_RETRIES);
00467                 /* fall through on else */
00468         case NL80211_PLINK_CNF_RCVD:
00469                 /* confirm timer */
00470                 if (!reason)
00471                         reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT);
00472                 sta->plink_state = NL80211_PLINK_HOLDING;
00473                 mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
00474                 spin_unlock_bh(&sta->lock);
00475                 mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
00476                                     sta->sta.addr, llid, plid, reason);
00477                 break;
00478         case NL80211_PLINK_HOLDING:
00479                 /* holding timer */
00480                 del_timer(&sta->plink_timer);
00481                 mesh_plink_fsm_restart(sta);
00482                 spin_unlock_bh(&sta->lock);
00483                 break;
00484         default:
00485                 spin_unlock_bh(&sta->lock);
00486                 break;
00487         }
00488 }
00489 
00490 #ifdef CONFIG_PM
00491 void mesh_plink_quiesce(struct sta_info *sta)
00492 {
00493         if (del_timer_sync(&sta->plink_timer))
00494                 sta->plink_timer_was_running = true;
00495 }
00496 
00497 void mesh_plink_restart(struct sta_info *sta)
00498 {
00499         if (sta->plink_timer_was_running) {
00500                 add_timer(&sta->plink_timer);
00501                 sta->plink_timer_was_running = false;
00502         }
00503 }
00504 #endif
00505 
00506 static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
00507 {
00508         sta->plink_timer.expires = jiffies + (HZ * timeout / 1000);
00509         sta->plink_timer.data = (unsigned long) sta;
00510         sta->plink_timer.function = mesh_plink_timer;
00511         sta->plink_timeout = timeout;
00512         add_timer(&sta->plink_timer);
00513 }
00514 
00515 int mesh_plink_open(struct sta_info *sta)
00516 {
00517         __le16 llid;
00518         struct ieee80211_sub_if_data *sdata = sta->sdata;
00519 
00520         if (!test_sta_flag(sta, WLAN_STA_AUTH))
00521                 return -EPERM;
00522 
00523         spin_lock_bh(&sta->lock);
00524         get_random_bytes(&llid, 2);
00525         sta->llid = llid;
00526         if (sta->plink_state != NL80211_PLINK_LISTEN) {
00527                 spin_unlock_bh(&sta->lock);
00528                 return -EBUSY;
00529         }
00530         sta->plink_state = NL80211_PLINK_OPN_SNT;
00531         mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
00532         spin_unlock_bh(&sta->lock);
00533         mpl_dbg("Mesh plink: starting establishment with %pM\n",
00534                 sta->sta.addr);
00535 
00536         return mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
00537                                    sta->sta.addr, llid, 0, 0);
00538 }
00539 
00540 void mesh_plink_block(struct sta_info *sta)
00541 {
00542         struct ieee80211_sub_if_data *sdata = sta->sdata;
00543         bool deactivated;
00544 
00545         spin_lock_bh(&sta->lock);
00546         deactivated = __mesh_plink_deactivate(sta);
00547         sta->plink_state = NL80211_PLINK_BLOCKED;
00548         spin_unlock_bh(&sta->lock);
00549 
00550         if (deactivated)
00551                 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
00552 }
00553 
00554 
00555 void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt,
00556                          size_t len, struct ieee80211_rx_status *rx_status)
00557 {
00558         struct ieee802_11_elems elems;
00559         struct sta_info *sta;
00560         enum plink_event event;
00561         enum ieee80211_self_protected_actioncode ftype;
00562         size_t baselen;
00563         bool matches_local = true;
00564         u8 ie_len;
00565         u8 *baseaddr;
00566         u32 changed = 0;
00567         __le16 plid, llid, reason;
00568 #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
00569         static const char *mplstates[] = {
00570                 [NL80211_PLINK_LISTEN] = "LISTEN",
00571                 [NL80211_PLINK_OPN_SNT] = "OPN-SNT",
00572                 [NL80211_PLINK_OPN_RCVD] = "OPN-RCVD",
00573                 [NL80211_PLINK_CNF_RCVD] = "CNF_RCVD",
00574                 [NL80211_PLINK_ESTAB] = "ESTAB",
00575                 [NL80211_PLINK_HOLDING] = "HOLDING",
00576                 [NL80211_PLINK_BLOCKED] = "BLOCKED"
00577         };
00578 #endif
00579 
00580         /* need action_code, aux */
00581         if (len < IEEE80211_MIN_ACTION_SIZE + 3)
00582                 return;
00583 
00584         if (is_multicast_ether_addr(mgmt->da)) {
00585                 mpl_dbg("Mesh plink: ignore frame from multicast address");
00586                 return;
00587         }
00588 
00589         baseaddr = mgmt->u.action.u.self_prot.variable;
00590         baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt;
00591         if (mgmt->u.action.u.self_prot.action_code ==
00592                                                 WLAN_SP_MESH_PEERING_CONFIRM) {
00593                 baseaddr += 4;
00594                 baselen += 4;
00595         }
00596         ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
00597         if (!elems.peering) {
00598                 mpl_dbg("Mesh plink: missing necessary peer link ie\n");
00599                 return;
00600         }
00601         if (elems.rsn_len &&
00602                         sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
00603                 mpl_dbg("Mesh plink: can't establish link with secure peer\n");
00604                 return;
00605         }
00606 
00607         ftype = mgmt->u.action.u.self_prot.action_code;
00608         ie_len = elems.peering_len;
00609         if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
00610             (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
00611             (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
00612                                                         && ie_len != 8)) {
00613                 mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n",
00614                     ftype, ie_len);
00615                 return;
00616         }
00617 
00618         if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
00619                                 (!elems.mesh_id || !elems.mesh_config)) {
00620                 mpl_dbg("Mesh plink: missing necessary ie\n");
00621                 return;
00622         }
00623         /* Note the lines below are correct, the llid in the frame is the plid
00624          * from the point of view of this host.
00625          */
00626         memcpy(&plid, PLINK_GET_LLID(elems.peering), 2);
00627         if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
00628             (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
00629                 memcpy(&llid, PLINK_GET_PLID(elems.peering), 2);
00630 
00631         rcu_read_lock();
00632 
00633         sta = sta_info_get(sdata, mgmt->sa);
00634         if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) {
00635                 mpl_dbg("Mesh plink: cls or cnf from unknown peer\n");
00636                 rcu_read_unlock();
00637                 return;
00638         }
00639 
00640         if (ftype == WLAN_SP_MESH_PEERING_OPEN &&
00641             !rssi_threshold_check(sta, sdata)) {
00642                 mpl_dbg("Mesh plink: %pM does not meet rssi threshold\n",
00643                         mgmt->sa);
00644                 rcu_read_unlock();
00645                 return;
00646         }
00647 
00648         if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) {
00649                 mpl_dbg("Mesh plink: Action frame from non-authed peer\n");
00650                 rcu_read_unlock();
00651                 return;
00652         }
00653 
00654         if (sta && sta->plink_state == NL80211_PLINK_BLOCKED) {
00655                 rcu_read_unlock();
00656                 return;
00657         }
00658 
00659         /* Now we will figure out the appropriate event... */
00660         event = PLINK_UNDEFINED;
00661         if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
00662             !mesh_matches_local(sdata, &elems)) {
00663                 matches_local = false;
00664                 switch (ftype) {
00665                 case WLAN_SP_MESH_PEERING_OPEN:
00666                         event = OPN_RJCT;
00667                         break;
00668                 case WLAN_SP_MESH_PEERING_CONFIRM:
00669                         event = CNF_RJCT;
00670                         break;
00671                 default:
00672                         break;
00673                 }
00674         }
00675 
00676         if (!sta && !matches_local) {
00677                 rcu_read_unlock();
00678                 reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
00679                 llid = 0;
00680                 mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
00681                                     mgmt->sa, llid, plid, reason);
00682                 return;
00683         } else if (!sta) {
00684                 /* ftype == WLAN_SP_MESH_PEERING_OPEN */
00685                 if (!mesh_plink_free_count(sdata)) {
00686                         mpl_dbg("Mesh plink error: no more free plinks\n");
00687                         rcu_read_unlock();
00688                         return;
00689                 }
00690                 event = OPN_ACPT;
00691         } else if (matches_local) {
00692                 switch (ftype) {
00693                 case WLAN_SP_MESH_PEERING_OPEN:
00694                         if (!mesh_plink_free_count(sdata) ||
00695                             (sta->plid && sta->plid != plid))
00696                                 event = OPN_IGNR;
00697                         else
00698                                 event = OPN_ACPT;
00699                         break;
00700                 case WLAN_SP_MESH_PEERING_CONFIRM:
00701                         if (!mesh_plink_free_count(sdata) ||
00702                             (sta->llid != llid || sta->plid != plid))
00703                                 event = CNF_IGNR;
00704                         else
00705                                 event = CNF_ACPT;
00706                         break;
00707                 case WLAN_SP_MESH_PEERING_CLOSE:
00708                         if (sta->plink_state == NL80211_PLINK_ESTAB)
00709                                 /* Do not check for llid or plid. This does not
00710                                  * follow the standard but since multiple plinks
00711                                  * per sta are not supported, it is necessary in
00712                                  * order to avoid a livelock when MP A sees an
00713                                  * establish peer link to MP B but MP B does not
00714                                  * see it. This can be caused by a timeout in
00715                                  * B's peer link establishment or B beign
00716                                  * restarted.
00717                                  */
00718                                 event = CLS_ACPT;
00719                         else if (sta->plid != plid)
00720                                 event = CLS_IGNR;
00721                         else if (ie_len == 7 && sta->llid != llid)
00722                                 event = CLS_IGNR;
00723                         else
00724                                 event = CLS_ACPT;
00725                         break;
00726                 default:
00727                         mpl_dbg("Mesh plink: unknown frame subtype\n");
00728                         rcu_read_unlock();
00729                         return;
00730                 }
00731         }
00732 
00733         if (event == OPN_ACPT) {
00734                 /* allocate sta entry if necessary and update info */
00735                 sta = mesh_peer_init(sdata, mgmt->sa, &elems);
00736                 if (!sta) {
00737                         mpl_dbg("Mesh plink: failed to init peer!\n");
00738                         rcu_read_unlock();
00739                         return;
00740                 }
00741         }
00742 
00743         mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n",
00744                 mgmt->sa, mplstates[sta->plink_state],
00745                 le16_to_cpu(sta->llid), le16_to_cpu(sta->plid),
00746                 event);
00747         reason = 0;
00748         spin_lock_bh(&sta->lock);
00749         switch (sta->plink_state) {
00750                 /* spin_unlock as soon as state is updated at each case */
00751         case NL80211_PLINK_LISTEN:
00752                 switch (event) {
00753                 case CLS_ACPT:
00754                         mesh_plink_fsm_restart(sta);
00755                         spin_unlock_bh(&sta->lock);
00756                         break;
00757                 case OPN_ACPT:
00758                         sta->plink_state = NL80211_PLINK_OPN_RCVD;
00759                         sta->plid = plid;
00760                         get_random_bytes(&llid, 2);
00761                         sta->llid = llid;
00762                         mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
00763                         spin_unlock_bh(&sta->lock);
00764                         mesh_plink_frame_tx(sdata,
00765                                             WLAN_SP_MESH_PEERING_OPEN,
00766                                             sta->sta.addr, llid, 0, 0);
00767                         mesh_plink_frame_tx(sdata,
00768                                             WLAN_SP_MESH_PEERING_CONFIRM,
00769                                             sta->sta.addr, llid, plid, 0);
00770                         break;
00771                 default:
00772                         spin_unlock_bh(&sta->lock);
00773                         break;
00774                 }
00775                 break;
00776 
00777         case NL80211_PLINK_OPN_SNT:
00778                 switch (event) {
00779                 case OPN_RJCT:
00780                 case CNF_RJCT:
00781                         reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
00782                 case CLS_ACPT:
00783                         if (!reason)
00784                                 reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
00785                         sta->reason = reason;
00786                         sta->plink_state = NL80211_PLINK_HOLDING;
00787                         if (!mod_plink_timer(sta,
00788                                              dot11MeshHoldingTimeout(sdata)))
00789                                 sta->ignore_plink_timer = true;
00790 
00791                         llid = sta->llid;
00792                         spin_unlock_bh(&sta->lock);
00793                         mesh_plink_frame_tx(sdata,
00794                                             WLAN_SP_MESH_PEERING_CLOSE,
00795                                             sta->sta.addr, llid, plid, reason);
00796                         break;
00797                 case OPN_ACPT:
00798                         /* retry timer is left untouched */
00799                         sta->plink_state = NL80211_PLINK_OPN_RCVD;
00800                         sta->plid = plid;
00801                         llid = sta->llid;
00802                         spin_unlock_bh(&sta->lock);
00803                         mesh_plink_frame_tx(sdata,
00804                                             WLAN_SP_MESH_PEERING_CONFIRM,
00805                                             sta->sta.addr, llid, plid, 0);
00806                         break;
00807                 case CNF_ACPT:
00808                         sta->plink_state = NL80211_PLINK_CNF_RCVD;
00809                         if (!mod_plink_timer(sta,
00810                                              dot11MeshConfirmTimeout(sdata)))
00811                                 sta->ignore_plink_timer = true;
00812 
00813                         spin_unlock_bh(&sta->lock);
00814                         break;
00815                 default:
00816                         spin_unlock_bh(&sta->lock);
00817                         break;
00818                 }
00819                 break;
00820 
00821         case NL80211_PLINK_OPN_RCVD:
00822                 switch (event) {
00823                 case OPN_RJCT:
00824                 case CNF_RJCT:
00825                         reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
00826                 case CLS_ACPT:
00827                         if (!reason)
00828                                 reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
00829                         sta->reason = reason;
00830                         sta->plink_state = NL80211_PLINK_HOLDING;
00831                         if (!mod_plink_timer(sta,
00832                                              dot11MeshHoldingTimeout(sdata)))
00833                                 sta->ignore_plink_timer = true;
00834 
00835                         llid = sta->llid;
00836                         spin_unlock_bh(&sta->lock);
00837                         mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
00838                                             sta->sta.addr, llid, plid, reason);
00839                         break;
00840                 case OPN_ACPT:
00841                         llid = sta->llid;
00842                         spin_unlock_bh(&sta->lock);
00843                         mesh_plink_frame_tx(sdata,
00844                                             WLAN_SP_MESH_PEERING_CONFIRM,
00845                                             sta->sta.addr, llid, plid, 0);
00846                         break;
00847                 case CNF_ACPT:
00848                         del_timer(&sta->plink_timer);
00849                         sta->plink_state = NL80211_PLINK_ESTAB;
00850                         spin_unlock_bh(&sta->lock);
00851                         mesh_plink_inc_estab_count(sdata);
00852                         changed |= mesh_set_ht_prot_mode(sdata);
00853                         changed |= BSS_CHANGED_BEACON;
00854                         mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
00855                                 sta->sta.addr);
00856                         break;
00857                 default:
00858                         spin_unlock_bh(&sta->lock);
00859                         break;
00860                 }
00861                 break;
00862 
00863         case NL80211_PLINK_CNF_RCVD:
00864                 switch (event) {
00865                 case OPN_RJCT:
00866                 case CNF_RJCT:
00867                         reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
00868                 case CLS_ACPT:
00869                         if (!reason)
00870                                 reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
00871                         sta->reason = reason;
00872                         sta->plink_state = NL80211_PLINK_HOLDING;
00873                         if (!mod_plink_timer(sta,
00874                                              dot11MeshHoldingTimeout(sdata)))
00875                                 sta->ignore_plink_timer = true;
00876 
00877                         llid = sta->llid;
00878                         spin_unlock_bh(&sta->lock);
00879                         mesh_plink_frame_tx(sdata,
00880                                             WLAN_SP_MESH_PEERING_CLOSE,
00881                                             sta->sta.addr, llid, plid, reason);
00882                         break;
00883                 case OPN_ACPT:
00884                         del_timer(&sta->plink_timer);
00885                         sta->plink_state = NL80211_PLINK_ESTAB;
00886                         spin_unlock_bh(&sta->lock);
00887                         mesh_plink_inc_estab_count(sdata);
00888                         changed |= mesh_set_ht_prot_mode(sdata);
00889                         changed |= BSS_CHANGED_BEACON;
00890                         mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
00891                                 sta->sta.addr);
00892                         mesh_plink_frame_tx(sdata,
00893                                             WLAN_SP_MESH_PEERING_CONFIRM,
00894                                             sta->sta.addr, llid, plid, 0);
00895                         break;
00896                 default:
00897                         spin_unlock_bh(&sta->lock);
00898                         break;
00899                 }
00900                 break;
00901 
00902         case NL80211_PLINK_ESTAB:
00903                 switch (event) {
00904                 case CLS_ACPT:
00905                         reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
00906                         sta->reason = reason;
00907                         __mesh_plink_deactivate(sta);
00908                         sta->plink_state = NL80211_PLINK_HOLDING;
00909                         llid = sta->llid;
00910                         mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
00911                         spin_unlock_bh(&sta->lock);
00912                         changed |= mesh_set_ht_prot_mode(sdata);
00913                         changed |= BSS_CHANGED_BEACON;
00914                         mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
00915                                             sta->sta.addr, llid, plid, reason);
00916                         break;
00917                 case OPN_ACPT:
00918                         llid = sta->llid;
00919                         spin_unlock_bh(&sta->lock);
00920                         mesh_plink_frame_tx(sdata,
00921                                             WLAN_SP_MESH_PEERING_CONFIRM,
00922                                             sta->sta.addr, llid, plid, 0);
00923                         break;
00924                 default:
00925                         spin_unlock_bh(&sta->lock);
00926                         break;
00927                 }
00928                 break;
00929         case NL80211_PLINK_HOLDING:
00930                 switch (event) {
00931                 case CLS_ACPT:
00932                         if (del_timer(&sta->plink_timer))
00933                                 sta->ignore_plink_timer = 1;
00934                         mesh_plink_fsm_restart(sta);
00935                         spin_unlock_bh(&sta->lock);
00936                         break;
00937                 case OPN_ACPT:
00938                 case CNF_ACPT:
00939                 case OPN_RJCT:
00940                 case CNF_RJCT:
00941                         llid = sta->llid;
00942                         reason = sta->reason;
00943                         spin_unlock_bh(&sta->lock);
00944                         mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
00945                                             sta->sta.addr, llid, plid, reason);
00946                         break;
00947                 default:
00948                         spin_unlock_bh(&sta->lock);
00949                 }
00950                 break;
00951         default:
00952                 /* should not get here, PLINK_BLOCKED is dealt with at the
00953                  * beginning of the function
00954                  */
00955                 spin_unlock_bh(&sta->lock);
00956                 break;
00957         }
00958 
00959         rcu_read_unlock();
00960 
00961         if (changed)
00962                 ieee80211_bss_info_change_notify(sdata, changed);
00963 }


ros_rt_wmp
Author(s): Danilo Tardioli, dantard@unizar.es
autogenerated on Mon Oct 6 2014 08:27:10