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 enum plink_event {
00035         PLINK_UNDEFINED,
00036         OPN_ACPT,
00037         OPN_RJCT,
00038         OPN_IGNR,
00039         CNF_ACPT,
00040         CNF_RJCT,
00041         CNF_IGNR,
00042         CLS_ACPT,
00043         CLS_IGNR
00044 };
00045 
00046 static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
00047                 enum ieee80211_self_protected_actioncode action,
00048                 u8 *da, __le16 llid, __le16 plid, __le16 reason);
00049 
00050 static inline
00051 void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
00052 {
00053         atomic_inc(&sdata->u.mesh.mshstats.estab_plinks);
00054         mesh_accept_plinks_update(sdata);
00055 }
00056 
00057 static inline
00058 void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
00059 {
00060         atomic_dec(&sdata->u.mesh.mshstats.estab_plinks);
00061         mesh_accept_plinks_update(sdata);
00062 }
00063 
00071 static inline void mesh_plink_fsm_restart(struct sta_info *sta)
00072 {
00073         sta->plink_state = NL80211_PLINK_LISTEN;
00074         sta->llid = sta->plid = sta->reason = 0;
00075         sta->plink_retries = 0;
00076 }
00077 
00078 /*
00079  * NOTE: This is just an alias for sta_info_alloc(), see notes
00080  *       on it in the lifecycle management section!
00081  */
00082 static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
00083                                          u8 *hw_addr, u32 rates)
00084 {
00085         struct ieee80211_local *local = sdata->local;
00086         struct sta_info *sta;
00087 
00088         if (local->num_sta >= MESH_MAX_PLINKS)
00089                 return NULL;
00090 
00091         sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL);
00092         if (!sta)
00093                 return NULL;
00094 
00095         set_sta_flag(sta, WLAN_STA_AUTH);
00096         set_sta_flag(sta, WLAN_STA_AUTHORIZED);
00097         set_sta_flag(sta, WLAN_STA_WME);
00098         sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
00099         rate_control_rate_init(sta);
00100 
00101         return sta;
00102 }
00103 
00113 static bool __mesh_plink_deactivate(struct sta_info *sta)
00114 {
00115         struct ieee80211_sub_if_data *sdata = sta->sdata;
00116         bool deactivated = false;
00117 
00118         if (sta->plink_state == NL80211_PLINK_ESTAB) {
00119                 mesh_plink_dec_estab_count(sdata);
00120                 deactivated = true;
00121         }
00122         sta->plink_state = NL80211_PLINK_BLOCKED;
00123         mesh_path_flush_by_nexthop(sta);
00124 
00125         return deactivated;
00126 }
00127 
00135 void mesh_plink_deactivate(struct sta_info *sta)
00136 {
00137         struct ieee80211_sub_if_data *sdata = sta->sdata;
00138         bool deactivated;
00139 
00140         spin_lock_bh(&sta->lock);
00141         deactivated = __mesh_plink_deactivate(sta);
00142         sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED);
00143         mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
00144                             sta->sta.addr, sta->llid, sta->plid,
00145                             sta->reason);
00146         spin_unlock_bh(&sta->lock);
00147 
00148         if (deactivated)
00149                 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
00150 }
00151 
00152 static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
00153                 enum ieee80211_self_protected_actioncode action,
00154                 u8 *da, __le16 llid, __le16 plid, __le16 reason) {
00155         struct ieee80211_local *local = sdata->local;
00156         struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
00157                         sdata->u.mesh.ie_len);
00158         struct ieee80211_mgmt *mgmt;
00159         bool include_plid = false;
00160         int ie_len = 4;
00161         u16 peering_proto = 0;
00162         u8 *pos;
00163 
00164         if (!skb)
00165                 return -1;
00166         skb_reserve(skb, local->hw.extra_tx_headroom);
00167         /* 25 is the size of the common mgmt part (24) plus the size of the
00168          * common action part (1)
00169          */
00170         mgmt = (struct ieee80211_mgmt *)
00171                 skb_put(skb, 25 + sizeof(mgmt->u.action.u.self_prot));
00172         memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.self_prot));
00173         mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
00174                                           IEEE80211_STYPE_ACTION);
00175         memcpy(mgmt->da, da, ETH_ALEN);
00176         memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
00177         memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
00178         mgmt->u.action.category = WLAN_CATEGORY_SELF_PROTECTED;
00179         mgmt->u.action.u.self_prot.action_code = action;
00180 
00181         if (action != WLAN_SP_MESH_PEERING_CLOSE) {
00182                 /* capability info */
00183                 pos = skb_put(skb, 2);
00184                 memset(pos, 0, 2);
00185                 if (action == WLAN_SP_MESH_PEERING_CONFIRM) {
00186                         /* AID */
00187                         pos = skb_put(skb, 2);
00188                         memcpy(pos + 2, &plid, 2);
00189                 }
00190                 if (ieee80211_add_srates_ie(&sdata->vif, skb) ||
00191                     ieee80211_add_ext_srates_ie(&sdata->vif, skb) ||
00192                     mesh_add_rsn_ie(skb, sdata) ||
00193                     mesh_add_meshid_ie(skb, sdata) ||
00194                     mesh_add_meshconf_ie(skb, sdata))
00195                         return -1;
00196         } else {        /* WLAN_SP_MESH_PEERING_CLOSE */
00197                 if (mesh_add_meshid_ie(skb, sdata))
00198                         return -1;
00199         }
00200 
00201         /* Add Mesh Peering Management element */
00202         switch (action) {
00203         case WLAN_SP_MESH_PEERING_OPEN:
00204                 break;
00205         case WLAN_SP_MESH_PEERING_CONFIRM:
00206                 ie_len += 2;
00207                 include_plid = true;
00208                 break;
00209         case WLAN_SP_MESH_PEERING_CLOSE:
00210                 if (plid) {
00211                         ie_len += 2;
00212                         include_plid = true;
00213                 }
00214                 ie_len += 2;    /* reason code */
00215                 break;
00216         default:
00217                 return -EINVAL;
00218         }
00219 
00220         if (WARN_ON(skb_tailroom(skb) < 2 + ie_len))
00221                 return -ENOMEM;
00222 
00223         pos = skb_put(skb, 2 + ie_len);
00224         *pos++ = WLAN_EID_PEER_MGMT;
00225         *pos++ = ie_len;
00226         memcpy(pos, &peering_proto, 2);
00227         pos += 2;
00228         memcpy(pos, &llid, 2);
00229         pos += 2;
00230         if (include_plid) {
00231                 memcpy(pos, &plid, 2);
00232                 pos += 2;
00233         }
00234         if (action == WLAN_SP_MESH_PEERING_CLOSE) {
00235                 memcpy(pos, &reason, 2);
00236                 pos += 2;
00237         }
00238         if (mesh_add_vendor_ies(skb, sdata))
00239                 return -1;
00240 
00241         ieee80211_tx_skb(sdata, skb);
00242         return 0;
00243 }
00244 
00245 void mesh_neighbour_update(u8 *hw_addr, u32 rates,
00246                 struct ieee80211_sub_if_data *sdata,
00247                 struct ieee802_11_elems *elems)
00248 {
00249         struct ieee80211_local *local = sdata->local;
00250         struct sta_info *sta;
00251 
00252         rcu_read_lock();
00253 
00254         sta = sta_info_get(sdata, hw_addr);
00255         if (!sta) {
00256                 rcu_read_unlock();
00257                 /* Userspace handles peer allocation when security is enabled
00258                  * */
00259                 if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED)
00260                         cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr,
00261                                         elems->ie_start, elems->total_len,
00262                                         GFP_KERNEL);
00263                 else
00264                         sta = mesh_plink_alloc(sdata, hw_addr, rates);
00265                 if (!sta)
00266                         return;
00267                 if (sta_info_insert_rcu(sta)) {
00268                         rcu_read_unlock();
00269                         return;
00270                 }
00271         }
00272 
00273         sta->last_rx = jiffies;
00274         sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
00275         if (mesh_peer_accepts_plinks(elems) &&
00276                         sta->plink_state == NL80211_PLINK_LISTEN &&
00277                         sdata->u.mesh.accepting_plinks &&
00278                         sdata->u.mesh.mshcfg.auto_open_plinks)
00279                 mesh_plink_open(sta);
00280 
00281         rcu_read_unlock();
00282 }
00283 
00284 static void mesh_plink_timer(unsigned long data)
00285 {
00286         struct sta_info *sta;
00287         __le16 llid, plid, reason;
00288         struct ieee80211_sub_if_data *sdata;
00289 
00290         /*
00291          * This STA is valid because sta_info_destroy() will
00292          * del_timer_sync() this timer after having made sure
00293          * it cannot be readded (by deleting the plink.)
00294          */
00295         sta = (struct sta_info *) data;
00296 
00297         if (sta->sdata->local->quiescing) {
00298                 sta->plink_timer_was_running = true;
00299                 return;
00300         }
00301 
00302         spin_lock_bh(&sta->lock);
00303         if (sta->ignore_plink_timer) {
00304                 sta->ignore_plink_timer = false;
00305                 spin_unlock_bh(&sta->lock);
00306                 return;
00307         }
00308         mpl_dbg("Mesh plink timer for %pM fired on state %d\n",
00309                 sta->sta.addr, sta->plink_state);
00310         reason = 0;
00311         llid = sta->llid;
00312         plid = sta->plid;
00313         sdata = sta->sdata;
00314 
00315         switch (sta->plink_state) {
00316         case NL80211_PLINK_OPN_RCVD:
00317         case NL80211_PLINK_OPN_SNT:
00318                 /* retry timer */
00319                 if (sta->plink_retries < dot11MeshMaxRetries(sdata)) {
00320                         u32 rand;
00321                         mpl_dbg("Mesh plink for %pM (retry, timeout): %d %d\n",
00322                                 sta->sta.addr, sta->plink_retries,
00323                                 sta->plink_timeout);
00324                         get_random_bytes(&rand, sizeof(u32));
00325                         sta->plink_timeout = sta->plink_timeout +
00326                                              rand % sta->plink_timeout;
00327                         ++sta->plink_retries;
00328                         mod_plink_timer(sta, sta->plink_timeout);
00329                         spin_unlock_bh(&sta->lock);
00330                         mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
00331                                             sta->sta.addr, llid, 0, 0);
00332                         break;
00333                 }
00334                 reason = cpu_to_le16(WLAN_REASON_MESH_MAX_RETRIES);
00335                 /* fall through on else */
00336         case NL80211_PLINK_CNF_RCVD:
00337                 /* confirm timer */
00338                 if (!reason)
00339                         reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT);
00340                 sta->plink_state = NL80211_PLINK_HOLDING;
00341                 mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
00342                 spin_unlock_bh(&sta->lock);
00343                 mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
00344                                     sta->sta.addr, llid, plid, reason);
00345                 break;
00346         case NL80211_PLINK_HOLDING:
00347                 /* holding timer */
00348                 del_timer(&sta->plink_timer);
00349                 mesh_plink_fsm_restart(sta);
00350                 spin_unlock_bh(&sta->lock);
00351                 break;
00352         default:
00353                 spin_unlock_bh(&sta->lock);
00354                 break;
00355         }
00356 }
00357 
00358 #ifdef CONFIG_PM
00359 void mesh_plink_quiesce(struct sta_info *sta)
00360 {
00361         if (del_timer_sync(&sta->plink_timer))
00362                 sta->plink_timer_was_running = true;
00363 }
00364 
00365 void mesh_plink_restart(struct sta_info *sta)
00366 {
00367         if (sta->plink_timer_was_running) {
00368                 add_timer(&sta->plink_timer);
00369                 sta->plink_timer_was_running = false;
00370         }
00371 }
00372 #endif
00373 
00374 static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
00375 {
00376         sta->plink_timer.expires = jiffies + (HZ * timeout / 1000);
00377         sta->plink_timer.data = (unsigned long) sta;
00378         sta->plink_timer.function = mesh_plink_timer;
00379         sta->plink_timeout = timeout;
00380         add_timer(&sta->plink_timer);
00381 }
00382 
00383 int mesh_plink_open(struct sta_info *sta)
00384 {
00385         __le16 llid;
00386         struct ieee80211_sub_if_data *sdata = sta->sdata;
00387 
00388         if (!test_sta_flag(sta, WLAN_STA_AUTH))
00389                 return -EPERM;
00390 
00391         spin_lock_bh(&sta->lock);
00392         get_random_bytes(&llid, 2);
00393         sta->llid = llid;
00394         if (sta->plink_state != NL80211_PLINK_LISTEN) {
00395                 spin_unlock_bh(&sta->lock);
00396                 return -EBUSY;
00397         }
00398         sta->plink_state = NL80211_PLINK_OPN_SNT;
00399         mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
00400         spin_unlock_bh(&sta->lock);
00401         mpl_dbg("Mesh plink: starting establishment with %pM\n",
00402                 sta->sta.addr);
00403 
00404         return mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN,
00405                                    sta->sta.addr, llid, 0, 0);
00406 }
00407 
00408 void mesh_plink_block(struct sta_info *sta)
00409 {
00410         struct ieee80211_sub_if_data *sdata = sta->sdata;
00411         bool deactivated;
00412 
00413         spin_lock_bh(&sta->lock);
00414         deactivated = __mesh_plink_deactivate(sta);
00415         sta->plink_state = NL80211_PLINK_BLOCKED;
00416         spin_unlock_bh(&sta->lock);
00417 
00418         if (deactivated)
00419                 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
00420 }
00421 
00422 
00423 void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt,
00424                          size_t len, struct ieee80211_rx_status *rx_status)
00425 {
00426         struct ieee80211_local *local = sdata->local;
00427         struct ieee802_11_elems elems;
00428         struct sta_info *sta;
00429         enum plink_event event;
00430         enum ieee80211_self_protected_actioncode ftype;
00431         size_t baselen;
00432         bool deactivated, matches_local = true;
00433         u8 ie_len;
00434         u8 *baseaddr;
00435         __le16 plid, llid, reason;
00436 #ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
00437         static const char *mplstates[] = {
00438                 [NL80211_PLINK_LISTEN] = "LISTEN",
00439                 [NL80211_PLINK_OPN_SNT] = "OPN-SNT",
00440                 [NL80211_PLINK_OPN_RCVD] = "OPN-RCVD",
00441                 [NL80211_PLINK_CNF_RCVD] = "CNF_RCVD",
00442                 [NL80211_PLINK_ESTAB] = "ESTAB",
00443                 [NL80211_PLINK_HOLDING] = "HOLDING",
00444                 [NL80211_PLINK_BLOCKED] = "BLOCKED"
00445         };
00446 #endif
00447 
00448         /* need action_code, aux */
00449         if (len < IEEE80211_MIN_ACTION_SIZE + 3)
00450                 return;
00451 
00452         if (is_multicast_ether_addr(mgmt->da)) {
00453                 mpl_dbg("Mesh plink: ignore frame from multicast address");
00454                 return;
00455         }
00456 
00457         baseaddr = mgmt->u.action.u.self_prot.variable;
00458         baselen = (u8 *) mgmt->u.action.u.self_prot.variable - (u8 *) mgmt;
00459         if (mgmt->u.action.u.self_prot.action_code ==
00460                                                 WLAN_SP_MESH_PEERING_CONFIRM) {
00461                 baseaddr += 4;
00462                 baselen += 4;
00463         }
00464         ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
00465         if (!elems.peering) {
00466                 mpl_dbg("Mesh plink: missing necessary peer link ie\n");
00467                 return;
00468         }
00469         if (elems.rsn_len &&
00470                         sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
00471                 mpl_dbg("Mesh plink: can't establish link with secure peer\n");
00472                 return;
00473         }
00474 
00475         ftype = mgmt->u.action.u.self_prot.action_code;
00476         ie_len = elems.peering_len;
00477         if ((ftype == WLAN_SP_MESH_PEERING_OPEN && ie_len != 4) ||
00478             (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) ||
00479             (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6
00480                                                         && ie_len != 8)) {
00481                 mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n",
00482                     ftype, ie_len);
00483                 return;
00484         }
00485 
00486         if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
00487                                 (!elems.mesh_id || !elems.mesh_config)) {
00488                 mpl_dbg("Mesh plink: missing necessary ie\n");
00489                 return;
00490         }
00491         /* Note the lines below are correct, the llid in the frame is the plid
00492          * from the point of view of this host.
00493          */
00494         memcpy(&plid, PLINK_GET_LLID(elems.peering), 2);
00495         if (ftype == WLAN_SP_MESH_PEERING_CONFIRM ||
00496             (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len == 8))
00497                 memcpy(&llid, PLINK_GET_PLID(elems.peering), 2);
00498 
00499         rcu_read_lock();
00500 
00501         sta = sta_info_get(sdata, mgmt->sa);
00502         if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) {
00503                 mpl_dbg("Mesh plink: cls or cnf from unknown peer\n");
00504                 rcu_read_unlock();
00505                 return;
00506         }
00507 
00508         if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) {
00509                 mpl_dbg("Mesh plink: Action frame from non-authed peer\n");
00510                 rcu_read_unlock();
00511                 return;
00512         }
00513 
00514         if (sta && sta->plink_state == NL80211_PLINK_BLOCKED) {
00515                 rcu_read_unlock();
00516                 return;
00517         }
00518 
00519         /* Now we will figure out the appropriate event... */
00520         event = PLINK_UNDEFINED;
00521         if (ftype != WLAN_SP_MESH_PEERING_CLOSE &&
00522             (!mesh_matches_local(&elems, sdata))) {
00523                 matches_local = false;
00524                 switch (ftype) {
00525                 case WLAN_SP_MESH_PEERING_OPEN:
00526                         event = OPN_RJCT;
00527                         break;
00528                 case WLAN_SP_MESH_PEERING_CONFIRM:
00529                         event = CNF_RJCT;
00530                         break;
00531                 default:
00532                         break;
00533                 }
00534         }
00535 
00536         if (!sta && !matches_local) {
00537                 rcu_read_unlock();
00538                 reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
00539                 llid = 0;
00540                 mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
00541                                     mgmt->sa, llid, plid, reason);
00542                 return;
00543         } else if (!sta) {
00544                 /* ftype == WLAN_SP_MESH_PEERING_OPEN */
00545                 u32 rates;
00546 
00547                 rcu_read_unlock();
00548 
00549                 if (!mesh_plink_free_count(sdata)) {
00550                         mpl_dbg("Mesh plink error: no more free plinks\n");
00551                         return;
00552                 }
00553 
00554                 rates = ieee80211_sta_get_rates(local, &elems, rx_status->band);
00555                 sta = mesh_plink_alloc(sdata, mgmt->sa, rates);
00556                 if (!sta) {
00557                         mpl_dbg("Mesh plink error: plink table full\n");
00558                         return;
00559                 }
00560                 if (sta_info_insert_rcu(sta)) {
00561                         rcu_read_unlock();
00562                         return;
00563                 }
00564                 event = OPN_ACPT;
00565                 spin_lock_bh(&sta->lock);
00566         } else if (matches_local) {
00567                 spin_lock_bh(&sta->lock);
00568                 switch (ftype) {
00569                 case WLAN_SP_MESH_PEERING_OPEN:
00570                         if (!mesh_plink_free_count(sdata) ||
00571                             (sta->plid && sta->plid != plid))
00572                                 event = OPN_IGNR;
00573                         else
00574                                 event = OPN_ACPT;
00575                         break;
00576                 case WLAN_SP_MESH_PEERING_CONFIRM:
00577                         if (!mesh_plink_free_count(sdata) ||
00578                             (sta->llid != llid || sta->plid != plid))
00579                                 event = CNF_IGNR;
00580                         else
00581                                 event = CNF_ACPT;
00582                         break;
00583                 case WLAN_SP_MESH_PEERING_CLOSE:
00584                         if (sta->plink_state == NL80211_PLINK_ESTAB)
00585                                 /* Do not check for llid or plid. This does not
00586                                  * follow the standard but since multiple plinks
00587                                  * per sta are not supported, it is necessary in
00588                                  * order to avoid a livelock when MP A sees an
00589                                  * establish peer link to MP B but MP B does not
00590                                  * see it. This can be caused by a timeout in
00591                                  * B's peer link establishment or B beign
00592                                  * restarted.
00593                                  */
00594                                 event = CLS_ACPT;
00595                         else if (sta->plid != plid)
00596                                 event = CLS_IGNR;
00597                         else if (ie_len == 7 && sta->llid != llid)
00598                                 event = CLS_IGNR;
00599                         else
00600                                 event = CLS_ACPT;
00601                         break;
00602                 default:
00603                         mpl_dbg("Mesh plink: unknown frame subtype\n");
00604                         spin_unlock_bh(&sta->lock);
00605                         rcu_read_unlock();
00606                         return;
00607                 }
00608         } else {
00609                 spin_lock_bh(&sta->lock);
00610         }
00611 
00612         mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n",
00613                 mgmt->sa, mplstates[sta->plink_state],
00614                 le16_to_cpu(sta->llid), le16_to_cpu(sta->plid),
00615                 event);
00616         reason = 0;
00617         switch (sta->plink_state) {
00618                 /* spin_unlock as soon as state is updated at each case */
00619         case NL80211_PLINK_LISTEN:
00620                 switch (event) {
00621                 case CLS_ACPT:
00622                         mesh_plink_fsm_restart(sta);
00623                         spin_unlock_bh(&sta->lock);
00624                         break;
00625                 case OPN_ACPT:
00626                         sta->plink_state = NL80211_PLINK_OPN_RCVD;
00627                         sta->plid = plid;
00628                         get_random_bytes(&llid, 2);
00629                         sta->llid = llid;
00630                         mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
00631                         spin_unlock_bh(&sta->lock);
00632                         mesh_plink_frame_tx(sdata,
00633                                             WLAN_SP_MESH_PEERING_OPEN,
00634                                             sta->sta.addr, llid, 0, 0);
00635                         mesh_plink_frame_tx(sdata,
00636                                             WLAN_SP_MESH_PEERING_CONFIRM,
00637                                             sta->sta.addr, llid, plid, 0);
00638                         break;
00639                 default:
00640                         spin_unlock_bh(&sta->lock);
00641                         break;
00642                 }
00643                 break;
00644 
00645         case NL80211_PLINK_OPN_SNT:
00646                 switch (event) {
00647                 case OPN_RJCT:
00648                 case CNF_RJCT:
00649                         reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
00650                 case CLS_ACPT:
00651                         if (!reason)
00652                                 reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
00653                         sta->reason = reason;
00654                         sta->plink_state = NL80211_PLINK_HOLDING;
00655                         if (!mod_plink_timer(sta,
00656                                              dot11MeshHoldingTimeout(sdata)))
00657                                 sta->ignore_plink_timer = true;
00658 
00659                         llid = sta->llid;
00660                         spin_unlock_bh(&sta->lock);
00661                         mesh_plink_frame_tx(sdata,
00662                                             WLAN_SP_MESH_PEERING_CLOSE,
00663                                             sta->sta.addr, llid, plid, reason);
00664                         break;
00665                 case OPN_ACPT:
00666                         /* retry timer is left untouched */
00667                         sta->plink_state = NL80211_PLINK_OPN_RCVD;
00668                         sta->plid = plid;
00669                         llid = sta->llid;
00670                         spin_unlock_bh(&sta->lock);
00671                         mesh_plink_frame_tx(sdata,
00672                                             WLAN_SP_MESH_PEERING_CONFIRM,
00673                                             sta->sta.addr, llid, plid, 0);
00674                         break;
00675                 case CNF_ACPT:
00676                         sta->plink_state = NL80211_PLINK_CNF_RCVD;
00677                         if (!mod_plink_timer(sta,
00678                                              dot11MeshConfirmTimeout(sdata)))
00679                                 sta->ignore_plink_timer = true;
00680 
00681                         spin_unlock_bh(&sta->lock);
00682                         break;
00683                 default:
00684                         spin_unlock_bh(&sta->lock);
00685                         break;
00686                 }
00687                 break;
00688 
00689         case NL80211_PLINK_OPN_RCVD:
00690                 switch (event) {
00691                 case OPN_RJCT:
00692                 case CNF_RJCT:
00693                         reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
00694                 case CLS_ACPT:
00695                         if (!reason)
00696                                 reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
00697                         sta->reason = reason;
00698                         sta->plink_state = NL80211_PLINK_HOLDING;
00699                         if (!mod_plink_timer(sta,
00700                                              dot11MeshHoldingTimeout(sdata)))
00701                                 sta->ignore_plink_timer = true;
00702 
00703                         llid = sta->llid;
00704                         spin_unlock_bh(&sta->lock);
00705                         mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
00706                                             sta->sta.addr, llid, plid, reason);
00707                         break;
00708                 case OPN_ACPT:
00709                         llid = sta->llid;
00710                         spin_unlock_bh(&sta->lock);
00711                         mesh_plink_frame_tx(sdata,
00712                                             WLAN_SP_MESH_PEERING_CONFIRM,
00713                                             sta->sta.addr, llid, plid, 0);
00714                         break;
00715                 case CNF_ACPT:
00716                         del_timer(&sta->plink_timer);
00717                         sta->plink_state = NL80211_PLINK_ESTAB;
00718                         spin_unlock_bh(&sta->lock);
00719                         mesh_plink_inc_estab_count(sdata);
00720                         ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
00721                         mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
00722                                 sta->sta.addr);
00723                         break;
00724                 default:
00725                         spin_unlock_bh(&sta->lock);
00726                         break;
00727                 }
00728                 break;
00729 
00730         case NL80211_PLINK_CNF_RCVD:
00731                 switch (event) {
00732                 case OPN_RJCT:
00733                 case CNF_RJCT:
00734                         reason = cpu_to_le16(WLAN_REASON_MESH_CONFIG);
00735                 case CLS_ACPT:
00736                         if (!reason)
00737                                 reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
00738                         sta->reason = reason;
00739                         sta->plink_state = NL80211_PLINK_HOLDING;
00740                         if (!mod_plink_timer(sta,
00741                                              dot11MeshHoldingTimeout(sdata)))
00742                                 sta->ignore_plink_timer = true;
00743 
00744                         llid = sta->llid;
00745                         spin_unlock_bh(&sta->lock);
00746                         mesh_plink_frame_tx(sdata,
00747                                             WLAN_SP_MESH_PEERING_CLOSE,
00748                                             sta->sta.addr, llid, plid, reason);
00749                         break;
00750                 case OPN_ACPT:
00751                         del_timer(&sta->plink_timer);
00752                         sta->plink_state = NL80211_PLINK_ESTAB;
00753                         spin_unlock_bh(&sta->lock);
00754                         mesh_plink_inc_estab_count(sdata);
00755                         ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
00756                         mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
00757                                 sta->sta.addr);
00758                         mesh_plink_frame_tx(sdata,
00759                                             WLAN_SP_MESH_PEERING_CONFIRM,
00760                                             sta->sta.addr, llid, plid, 0);
00761                         break;
00762                 default:
00763                         spin_unlock_bh(&sta->lock);
00764                         break;
00765                 }
00766                 break;
00767 
00768         case NL80211_PLINK_ESTAB:
00769                 switch (event) {
00770                 case CLS_ACPT:
00771                         reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
00772                         sta->reason = reason;
00773                         deactivated = __mesh_plink_deactivate(sta);
00774                         sta->plink_state = NL80211_PLINK_HOLDING;
00775                         llid = sta->llid;
00776                         mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
00777                         spin_unlock_bh(&sta->lock);
00778                         if (deactivated)
00779                                 ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
00780                         mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
00781                                             sta->sta.addr, llid, plid, reason);
00782                         break;
00783                 case OPN_ACPT:
00784                         llid = sta->llid;
00785                         spin_unlock_bh(&sta->lock);
00786                         mesh_plink_frame_tx(sdata,
00787                                             WLAN_SP_MESH_PEERING_CONFIRM,
00788                                             sta->sta.addr, llid, plid, 0);
00789                         break;
00790                 default:
00791                         spin_unlock_bh(&sta->lock);
00792                         break;
00793                 }
00794                 break;
00795         case NL80211_PLINK_HOLDING:
00796                 switch (event) {
00797                 case CLS_ACPT:
00798                         if (del_timer(&sta->plink_timer))
00799                                 sta->ignore_plink_timer = 1;
00800                         mesh_plink_fsm_restart(sta);
00801                         spin_unlock_bh(&sta->lock);
00802                         break;
00803                 case OPN_ACPT:
00804                 case CNF_ACPT:
00805                 case OPN_RJCT:
00806                 case CNF_RJCT:
00807                         llid = sta->llid;
00808                         reason = sta->reason;
00809                         spin_unlock_bh(&sta->lock);
00810                         mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
00811                                             sta->sta.addr, llid, plid, reason);
00812                         break;
00813                 default:
00814                         spin_unlock_bh(&sta->lock);
00815                 }
00816                 break;
00817         default:
00818                 /* should not get here, PLINK_BLOCKED is dealt with at the
00819                  * beginning of the function
00820                  */
00821                 spin_unlock_bh(&sta->lock);
00822                 break;
00823         }
00824 
00825         rcu_read_unlock();
00826 }


ros_rt_wmp
Author(s): Danilo Tardioli, dantard@unizar.es
autogenerated on Fri Jan 3 2014 12:07:55