linux/net/mac80211/mesh_plink.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2008 open80211s Ltd.
   3 * Author:     Luis Carlos Cobo <luisca@cozybit.com>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 */
   9#include <linux/kernel.h>
  10#include <linux/random.h>
  11#include "ieee80211_i.h"
  12#include "rate.h"
  13#include "mesh.h"
  14
  15#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
  16#define mpl_dbg(fmt, args...)   printk(KERN_DEBUG fmt, ##args)
  17#else
  18#define mpl_dbg(fmt, args...)   do { (void)(0); } while (0)
  19#endif
  20
  21#define PLINK_GET_FRAME_SUBTYPE(p) (p)
  22#define PLINK_GET_LLID(p) (p + 1)
  23#define PLINK_GET_PLID(p) (p + 3)
  24
  25#define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
  26                                jiffies + HZ * t / 1000))
  27
  28/* Peer link cancel reasons, all subject to ANA approval */
  29#define MESH_LINK_CANCELLED                     2
  30#define MESH_MAX_NEIGHBORS                      3
  31#define MESH_CAPABILITY_POLICY_VIOLATION        4
  32#define MESH_CLOSE_RCVD                         5
  33#define MESH_MAX_RETRIES                        6
  34#define MESH_CONFIRM_TIMEOUT                    7
  35#define MESH_SECURITY_ROLE_NEGOTIATION_DIFFERS  8
  36#define MESH_SECURITY_AUTHENTICATION_IMPOSSIBLE 9
  37#define MESH_SECURITY_FAILED_VERIFICATION       10
  38
  39#define dot11MeshMaxRetries(s) (s->u.mesh.mshcfg.dot11MeshMaxRetries)
  40#define dot11MeshRetryTimeout(s) (s->u.mesh.mshcfg.dot11MeshRetryTimeout)
  41#define dot11MeshConfirmTimeout(s) (s->u.mesh.mshcfg.dot11MeshConfirmTimeout)
  42#define dot11MeshHoldingTimeout(s) (s->u.mesh.mshcfg.dot11MeshHoldingTimeout)
  43#define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks)
  44
  45enum plink_frame_type {
  46        PLINK_OPEN = 0,
  47        PLINK_CONFIRM,
  48        PLINK_CLOSE
  49};
  50
  51enum plink_event {
  52        PLINK_UNDEFINED,
  53        OPN_ACPT,
  54        OPN_RJCT,
  55        OPN_IGNR,
  56        CNF_ACPT,
  57        CNF_RJCT,
  58        CNF_IGNR,
  59        CLS_ACPT,
  60        CLS_IGNR
  61};
  62
  63static inline
  64void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
  65{
  66        atomic_inc(&sdata->u.mesh.mshstats.estab_plinks);
  67        mesh_accept_plinks_update(sdata);
  68}
  69
  70static inline
  71void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
  72{
  73        atomic_dec(&sdata->u.mesh.mshstats.estab_plinks);
  74        mesh_accept_plinks_update(sdata);
  75}
  76
  77/**
  78 * mesh_plink_fsm_restart - restart a mesh peer link finite state machine
  79 *
  80 * @sta: mes peer link to restart
  81 *
  82 * Locking: this function must be called holding sta->lock
  83 */
  84static inline void mesh_plink_fsm_restart(struct sta_info *sta)
  85{
  86        sta->plink_state = PLINK_LISTEN;
  87        sta->llid = sta->plid = sta->reason = 0;
  88        sta->plink_retries = 0;
  89}
  90
  91/*
  92 * NOTE: This is just an alias for sta_info_alloc(), see notes
  93 *       on it in the lifecycle management section!
  94 */
  95static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
  96                                         u8 *hw_addr, u32 rates)
  97{
  98        struct ieee80211_local *local = sdata->local;
  99        struct sta_info *sta;
 100
 101        if (local->num_sta >= MESH_MAX_PLINKS)
 102                return NULL;
 103
 104        sta = sta_info_alloc(sdata, hw_addr, GFP_ATOMIC);
 105        if (!sta)
 106                return NULL;
 107
 108        sta->flags = WLAN_STA_AUTHORIZED;
 109        sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
 110        rate_control_rate_init(sta);
 111
 112        return sta;
 113}
 114
 115/**
 116 * mesh_plink_deactivate - deactivate mesh peer link
 117 *
 118 * @sta: mesh peer link to deactivate
 119 *
 120 * All mesh paths with this peer as next hop will be flushed
 121 *
 122 * Locking: the caller must hold sta->lock
 123 */
 124static void __mesh_plink_deactivate(struct sta_info *sta)
 125{
 126        struct ieee80211_sub_if_data *sdata = sta->sdata;
 127
 128        if (sta->plink_state == PLINK_ESTAB)
 129                mesh_plink_dec_estab_count(sdata);
 130        sta->plink_state = PLINK_BLOCKED;
 131        mesh_path_flush_by_nexthop(sta);
 132}
 133
 134/**
 135 * __mesh_plink_deactivate - deactivate mesh peer link
 136 *
 137 * @sta: mesh peer link to deactivate
 138 *
 139 * All mesh paths with this peer as next hop will be flushed
 140 */
 141void mesh_plink_deactivate(struct sta_info *sta)
 142{
 143        spin_lock_bh(&sta->lock);
 144        __mesh_plink_deactivate(sta);
 145        spin_unlock_bh(&sta->lock);
 146}
 147
 148static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
 149                enum plink_frame_type action, u8 *da, __le16 llid, __le16 plid,
 150                __le16 reason) {
 151        struct ieee80211_local *local = sdata->local;
 152        struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
 153        struct ieee80211_mgmt *mgmt;
 154        bool include_plid = false;
 155        u8 *pos;
 156        int ie_len;
 157
 158        if (!skb)
 159                return -1;
 160        skb_reserve(skb, local->hw.extra_tx_headroom);
 161        /* 25 is the size of the common mgmt part (24) plus the size of the
 162         * common action part (1)
 163         */
 164        mgmt = (struct ieee80211_mgmt *)
 165                skb_put(skb, 25 + sizeof(mgmt->u.action.u.plink_action));
 166        memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.plink_action));
 167        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
 168                                          IEEE80211_STYPE_ACTION);
 169        memcpy(mgmt->da, da, ETH_ALEN);
 170        memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
 171        /* BSSID is left zeroed, wildcard value */
 172        mgmt->u.action.category = PLINK_CATEGORY;
 173        mgmt->u.action.u.plink_action.action_code = action;
 174
 175        if (action == PLINK_CLOSE)
 176                mgmt->u.action.u.plink_action.aux = reason;
 177        else {
 178                mgmt->u.action.u.plink_action.aux = cpu_to_le16(0x0);
 179                if (action == PLINK_CONFIRM) {
 180                        pos = skb_put(skb, 4);
 181                        /* two-byte status code followed by two-byte AID */
 182                        memset(pos, 0, 4);
 183                }
 184                mesh_mgmt_ies_add(skb, sdata);
 185        }
 186
 187        /* Add Peer Link Management element */
 188        switch (action) {
 189        case PLINK_OPEN:
 190                ie_len = 3;
 191                break;
 192        case PLINK_CONFIRM:
 193                ie_len = 5;
 194                include_plid = true;
 195                break;
 196        case PLINK_CLOSE:
 197        default:
 198                if (!plid)
 199                        ie_len = 5;
 200                else {
 201                        ie_len = 7;
 202                        include_plid = true;
 203                }
 204                break;
 205        }
 206
 207        pos = skb_put(skb, 2 + ie_len);
 208        *pos++ = WLAN_EID_PEER_LINK;
 209        *pos++ = ie_len;
 210        *pos++ = action;
 211        memcpy(pos, &llid, 2);
 212        if (include_plid) {
 213                pos += 2;
 214                memcpy(pos, &plid, 2);
 215        }
 216        if (action == PLINK_CLOSE) {
 217                pos += 2;
 218                memcpy(pos, &reason, 2);
 219        }
 220
 221        ieee80211_tx_skb(sdata, skb, 1);
 222        return 0;
 223}
 224
 225void mesh_neighbour_update(u8 *hw_addr, u32 rates, struct ieee80211_sub_if_data *sdata,
 226                           bool peer_accepting_plinks)
 227{
 228        struct ieee80211_local *local = sdata->local;
 229        struct sta_info *sta;
 230
 231        rcu_read_lock();
 232
 233        sta = sta_info_get(local, hw_addr);
 234        if (!sta) {
 235                sta = mesh_plink_alloc(sdata, hw_addr, rates);
 236                if (!sta) {
 237                        rcu_read_unlock();
 238                        return;
 239                }
 240                if (sta_info_insert(sta)) {
 241                        rcu_read_unlock();
 242                        return;
 243                }
 244        }
 245
 246        sta->last_rx = jiffies;
 247        sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
 248        if (peer_accepting_plinks && sta->plink_state == PLINK_LISTEN &&
 249                        sdata->u.mesh.accepting_plinks &&
 250                        sdata->u.mesh.mshcfg.auto_open_plinks)
 251                mesh_plink_open(sta);
 252
 253        rcu_read_unlock();
 254}
 255
 256static void mesh_plink_timer(unsigned long data)
 257{
 258        struct sta_info *sta;
 259        __le16 llid, plid, reason;
 260        struct ieee80211_sub_if_data *sdata;
 261
 262        /*
 263         * This STA is valid because sta_info_destroy() will
 264         * del_timer_sync() this timer after having made sure
 265         * it cannot be readded (by deleting the plink.)
 266         */
 267        sta = (struct sta_info *) data;
 268
 269        if (sta->sdata->local->quiescing) {
 270                sta->plink_timer_was_running = true;
 271                return;
 272        }
 273
 274        spin_lock_bh(&sta->lock);
 275        if (sta->ignore_plink_timer) {
 276                sta->ignore_plink_timer = false;
 277                spin_unlock_bh(&sta->lock);
 278                return;
 279        }
 280        mpl_dbg("Mesh plink timer for %pM fired on state %d\n",
 281                sta->sta.addr, sta->plink_state);
 282        reason = 0;
 283        llid = sta->llid;
 284        plid = sta->plid;
 285        sdata = sta->sdata;
 286
 287        switch (sta->plink_state) {
 288        case PLINK_OPN_RCVD:
 289        case PLINK_OPN_SNT:
 290                /* retry timer */
 291                if (sta->plink_retries < dot11MeshMaxRetries(sdata)) {
 292                        u32 rand;
 293                        mpl_dbg("Mesh plink for %pM (retry, timeout): %d %d\n",
 294                                sta->sta.addr, sta->plink_retries,
 295                                sta->plink_timeout);
 296                        get_random_bytes(&rand, sizeof(u32));
 297                        sta->plink_timeout = sta->plink_timeout +
 298                                             rand % sta->plink_timeout;
 299                        ++sta->plink_retries;
 300                        mod_plink_timer(sta, sta->plink_timeout);
 301                        spin_unlock_bh(&sta->lock);
 302                        mesh_plink_frame_tx(sdata, PLINK_OPEN, sta->sta.addr, llid,
 303                                            0, 0);
 304                        break;
 305                }
 306                reason = cpu_to_le16(MESH_MAX_RETRIES);
 307                /* fall through on else */
 308        case PLINK_CNF_RCVD:
 309                /* confirm timer */
 310                if (!reason)
 311                        reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT);
 312                sta->plink_state = PLINK_HOLDING;
 313                mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
 314                spin_unlock_bh(&sta->lock);
 315                mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid,
 316                                    reason);
 317                break;
 318        case PLINK_HOLDING:
 319                /* holding timer */
 320                del_timer(&sta->plink_timer);
 321                mesh_plink_fsm_restart(sta);
 322                spin_unlock_bh(&sta->lock);
 323                break;
 324        default:
 325                spin_unlock_bh(&sta->lock);
 326                break;
 327        }
 328}
 329
 330#ifdef CONFIG_PM
 331void mesh_plink_quiesce(struct sta_info *sta)
 332{
 333        if (del_timer_sync(&sta->plink_timer))
 334                sta->plink_timer_was_running = true;
 335}
 336
 337void mesh_plink_restart(struct sta_info *sta)
 338{
 339        if (sta->plink_timer_was_running) {
 340                add_timer(&sta->plink_timer);
 341                sta->plink_timer_was_running = false;
 342        }
 343}
 344#endif
 345
 346static inline void mesh_plink_timer_set(struct sta_info *sta, int timeout)
 347{
 348        sta->plink_timer.expires = jiffies + (HZ * timeout / 1000);
 349        sta->plink_timer.data = (unsigned long) sta;
 350        sta->plink_timer.function = mesh_plink_timer;
 351        sta->plink_timeout = timeout;
 352        add_timer(&sta->plink_timer);
 353}
 354
 355int mesh_plink_open(struct sta_info *sta)
 356{
 357        __le16 llid;
 358        struct ieee80211_sub_if_data *sdata = sta->sdata;
 359
 360        spin_lock_bh(&sta->lock);
 361        get_random_bytes(&llid, 2);
 362        sta->llid = llid;
 363        if (sta->plink_state != PLINK_LISTEN) {
 364                spin_unlock_bh(&sta->lock);
 365                return -EBUSY;
 366        }
 367        sta->plink_state = PLINK_OPN_SNT;
 368        mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
 369        spin_unlock_bh(&sta->lock);
 370        mpl_dbg("Mesh plink: starting establishment with %pM\n",
 371                sta->sta.addr);
 372
 373        return mesh_plink_frame_tx(sdata, PLINK_OPEN,
 374                                   sta->sta.addr, llid, 0, 0);
 375}
 376
 377void mesh_plink_block(struct sta_info *sta)
 378{
 379        spin_lock_bh(&sta->lock);
 380        __mesh_plink_deactivate(sta);
 381        sta->plink_state = PLINK_BLOCKED;
 382        spin_unlock_bh(&sta->lock);
 383}
 384
 385
 386void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt,
 387                         size_t len, struct ieee80211_rx_status *rx_status)
 388{
 389        struct ieee80211_local *local = sdata->local;
 390        struct ieee802_11_elems elems;
 391        struct sta_info *sta;
 392        enum plink_event event;
 393        enum plink_frame_type ftype;
 394        size_t baselen;
 395        u8 ie_len;
 396        u8 *baseaddr;
 397        __le16 plid, llid, reason;
 398
 399        /* need action_code, aux */
 400        if (len < IEEE80211_MIN_ACTION_SIZE + 3)
 401                return;
 402
 403        if (is_multicast_ether_addr(mgmt->da)) {
 404                mpl_dbg("Mesh plink: ignore frame from multicast address");
 405                return;
 406        }
 407
 408        baseaddr = mgmt->u.action.u.plink_action.variable;
 409        baselen = (u8 *) mgmt->u.action.u.plink_action.variable - (u8 *) mgmt;
 410        if (mgmt->u.action.u.plink_action.action_code == PLINK_CONFIRM) {
 411                baseaddr += 4;
 412                baselen += 4;
 413        }
 414        ieee802_11_parse_elems(baseaddr, len - baselen, &elems);
 415        if (!elems.peer_link) {
 416                mpl_dbg("Mesh plink: missing necessary peer link ie\n");
 417                return;
 418        }
 419
 420        ftype = *((u8 *)PLINK_GET_FRAME_SUBTYPE(elems.peer_link));
 421        ie_len = elems.peer_link_len;
 422        if ((ftype == PLINK_OPEN && ie_len != 3) ||
 423            (ftype == PLINK_CONFIRM && ie_len != 5) ||
 424            (ftype == PLINK_CLOSE && ie_len != 5 && ie_len != 7)) {
 425                mpl_dbg("Mesh plink: incorrect plink ie length\n");
 426                return;
 427        }
 428
 429        if (ftype != PLINK_CLOSE && (!elems.mesh_id || !elems.mesh_config)) {
 430                mpl_dbg("Mesh plink: missing necessary ie\n");
 431                return;
 432        }
 433        /* Note the lines below are correct, the llid in the frame is the plid
 434         * from the point of view of this host.
 435         */
 436        memcpy(&plid, PLINK_GET_LLID(elems.peer_link), 2);
 437        if (ftype == PLINK_CONFIRM || (ftype == PLINK_CLOSE && ie_len == 7))
 438                memcpy(&llid, PLINK_GET_PLID(elems.peer_link), 2);
 439
 440        rcu_read_lock();
 441
 442        sta = sta_info_get(local, mgmt->sa);
 443        if (!sta && ftype != PLINK_OPEN) {
 444                mpl_dbg("Mesh plink: cls or cnf from unknown peer\n");
 445                rcu_read_unlock();
 446                return;
 447        }
 448
 449        if (sta && sta->plink_state == PLINK_BLOCKED) {
 450                rcu_read_unlock();
 451                return;
 452        }
 453
 454        /* Now we will figure out the appropriate event... */
 455        event = PLINK_UNDEFINED;
 456        if (ftype != PLINK_CLOSE && (!mesh_matches_local(&elems, sdata))) {
 457                switch (ftype) {
 458                case PLINK_OPEN:
 459                        event = OPN_RJCT;
 460                        break;
 461                case PLINK_CONFIRM:
 462                        event = CNF_RJCT;
 463                        break;
 464                case PLINK_CLOSE:
 465                        /* avoid warning */
 466                        break;
 467                }
 468                spin_lock_bh(&sta->lock);
 469        } else if (!sta) {
 470                /* ftype == PLINK_OPEN */
 471                u32 rates;
 472                if (!mesh_plink_free_count(sdata)) {
 473                        mpl_dbg("Mesh plink error: no more free plinks\n");
 474                        rcu_read_unlock();
 475                        return;
 476                }
 477
 478                rates = ieee80211_sta_get_rates(local, &elems, rx_status->band);
 479                sta = mesh_plink_alloc(sdata, mgmt->sa, rates);
 480                if (!sta) {
 481                        mpl_dbg("Mesh plink error: plink table full\n");
 482                        rcu_read_unlock();
 483                        return;
 484                }
 485                if (sta_info_insert(sta)) {
 486                        rcu_read_unlock();
 487                        return;
 488                }
 489                event = OPN_ACPT;
 490                spin_lock_bh(&sta->lock);
 491        } else {
 492                spin_lock_bh(&sta->lock);
 493                switch (ftype) {
 494                case PLINK_OPEN:
 495                        if (!mesh_plink_free_count(sdata) ||
 496                            (sta->plid && sta->plid != plid))
 497                                event = OPN_IGNR;
 498                        else
 499                                event = OPN_ACPT;
 500                        break;
 501                case PLINK_CONFIRM:
 502                        if (!mesh_plink_free_count(sdata) ||
 503                            (sta->llid != llid || sta->plid != plid))
 504                                event = CNF_IGNR;
 505                        else
 506                                event = CNF_ACPT;
 507                        break;
 508                case PLINK_CLOSE:
 509                        if (sta->plink_state == PLINK_ESTAB)
 510                                /* Do not check for llid or plid. This does not
 511                                 * follow the standard but since multiple plinks
 512                                 * per sta are not supported, it is necessary in
 513                                 * order to avoid a livelock when MP A sees an
 514                                 * establish peer link to MP B but MP B does not
 515                                 * see it. This can be caused by a timeout in
 516                                 * B's peer link establishment or B beign
 517                                 * restarted.
 518                                 */
 519                                event = CLS_ACPT;
 520                        else if (sta->plid != plid)
 521                                event = CLS_IGNR;
 522                        else if (ie_len == 7 && sta->llid != llid)
 523                                event = CLS_IGNR;
 524                        else
 525                                event = CLS_ACPT;
 526                        break;
 527                default:
 528                        mpl_dbg("Mesh plink: unknown frame subtype\n");
 529                        spin_unlock_bh(&sta->lock);
 530                        rcu_read_unlock();
 531                        return;
 532                }
 533        }
 534
 535        mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %d %d %d %d\n",
 536                mgmt->sa, sta->plink_state,
 537                le16_to_cpu(sta->llid), le16_to_cpu(sta->plid),
 538                event);
 539        reason = 0;
 540        switch (sta->plink_state) {
 541                /* spin_unlock as soon as state is updated at each case */
 542        case PLINK_LISTEN:
 543                switch (event) {
 544                case CLS_ACPT:
 545                        mesh_plink_fsm_restart(sta);
 546                        spin_unlock_bh(&sta->lock);
 547                        break;
 548                case OPN_ACPT:
 549                        sta->plink_state = PLINK_OPN_RCVD;
 550                        sta->plid = plid;
 551                        get_random_bytes(&llid, 2);
 552                        sta->llid = llid;
 553                        mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
 554                        spin_unlock_bh(&sta->lock);
 555                        mesh_plink_frame_tx(sdata, PLINK_OPEN, sta->sta.addr, llid,
 556                                            0, 0);
 557                        mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr,
 558                                            llid, plid, 0);
 559                        break;
 560                default:
 561                        spin_unlock_bh(&sta->lock);
 562                        break;
 563                }
 564                break;
 565
 566        case PLINK_OPN_SNT:
 567                switch (event) {
 568                case OPN_RJCT:
 569                case CNF_RJCT:
 570                        reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
 571                case CLS_ACPT:
 572                        if (!reason)
 573                                reason = cpu_to_le16(MESH_CLOSE_RCVD);
 574                        sta->reason = reason;
 575                        sta->plink_state = PLINK_HOLDING;
 576                        if (!mod_plink_timer(sta,
 577                                             dot11MeshHoldingTimeout(sdata)))
 578                                sta->ignore_plink_timer = true;
 579
 580                        llid = sta->llid;
 581                        spin_unlock_bh(&sta->lock);
 582                        mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
 583                                            plid, reason);
 584                        break;
 585                case OPN_ACPT:
 586                        /* retry timer is left untouched */
 587                        sta->plink_state = PLINK_OPN_RCVD;
 588                        sta->plid = plid;
 589                        llid = sta->llid;
 590                        spin_unlock_bh(&sta->lock);
 591                        mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
 592                                            plid, 0);
 593                        break;
 594                case CNF_ACPT:
 595                        sta->plink_state = PLINK_CNF_RCVD;
 596                        if (!mod_plink_timer(sta,
 597                                             dot11MeshConfirmTimeout(sdata)))
 598                                sta->ignore_plink_timer = true;
 599
 600                        spin_unlock_bh(&sta->lock);
 601                        break;
 602                default:
 603                        spin_unlock_bh(&sta->lock);
 604                        break;
 605                }
 606                break;
 607
 608        case PLINK_OPN_RCVD:
 609                switch (event) {
 610                case OPN_RJCT:
 611                case CNF_RJCT:
 612                        reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
 613                case CLS_ACPT:
 614                        if (!reason)
 615                                reason = cpu_to_le16(MESH_CLOSE_RCVD);
 616                        sta->reason = reason;
 617                        sta->plink_state = PLINK_HOLDING;
 618                        if (!mod_plink_timer(sta,
 619                                             dot11MeshHoldingTimeout(sdata)))
 620                                sta->ignore_plink_timer = true;
 621
 622                        llid = sta->llid;
 623                        spin_unlock_bh(&sta->lock);
 624                        mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
 625                                            plid, reason);
 626                        break;
 627                case OPN_ACPT:
 628                        llid = sta->llid;
 629                        spin_unlock_bh(&sta->lock);
 630                        mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
 631                                            plid, 0);
 632                        break;
 633                case CNF_ACPT:
 634                        del_timer(&sta->plink_timer);
 635                        sta->plink_state = PLINK_ESTAB;
 636                        mesh_plink_inc_estab_count(sdata);
 637                        spin_unlock_bh(&sta->lock);
 638                        mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
 639                                sta->sta.addr);
 640                        break;
 641                default:
 642                        spin_unlock_bh(&sta->lock);
 643                        break;
 644                }
 645                break;
 646
 647        case PLINK_CNF_RCVD:
 648                switch (event) {
 649                case OPN_RJCT:
 650                case CNF_RJCT:
 651                        reason = cpu_to_le16(MESH_CAPABILITY_POLICY_VIOLATION);
 652                case CLS_ACPT:
 653                        if (!reason)
 654                                reason = cpu_to_le16(MESH_CLOSE_RCVD);
 655                        sta->reason = reason;
 656                        sta->plink_state = PLINK_HOLDING;
 657                        if (!mod_plink_timer(sta,
 658                                             dot11MeshHoldingTimeout(sdata)))
 659                                sta->ignore_plink_timer = true;
 660
 661                        llid = sta->llid;
 662                        spin_unlock_bh(&sta->lock);
 663                        mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
 664                                            plid, reason);
 665                        break;
 666                case OPN_ACPT:
 667                        del_timer(&sta->plink_timer);
 668                        sta->plink_state = PLINK_ESTAB;
 669                        mesh_plink_inc_estab_count(sdata);
 670                        spin_unlock_bh(&sta->lock);
 671                        mpl_dbg("Mesh plink with %pM ESTABLISHED\n",
 672                                sta->sta.addr);
 673                        mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
 674                                            plid, 0);
 675                        break;
 676                default:
 677                        spin_unlock_bh(&sta->lock);
 678                        break;
 679                }
 680                break;
 681
 682        case PLINK_ESTAB:
 683                switch (event) {
 684                case CLS_ACPT:
 685                        reason = cpu_to_le16(MESH_CLOSE_RCVD);
 686                        sta->reason = reason;
 687                        __mesh_plink_deactivate(sta);
 688                        sta->plink_state = PLINK_HOLDING;
 689                        llid = sta->llid;
 690                        mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
 691                        spin_unlock_bh(&sta->lock);
 692                        mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid,
 693                                            plid, reason);
 694                        break;
 695                case OPN_ACPT:
 696                        llid = sta->llid;
 697                        spin_unlock_bh(&sta->lock);
 698                        mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid,
 699                                            plid, 0);
 700                        break;
 701                default:
 702                        spin_unlock_bh(&sta->lock);
 703                        break;
 704                }
 705                break;
 706        case PLINK_HOLDING:
 707                switch (event) {
 708                case CLS_ACPT:
 709                        if (del_timer(&sta->plink_timer))
 710                                sta->ignore_plink_timer = 1;
 711                        mesh_plink_fsm_restart(sta);
 712                        spin_unlock_bh(&sta->lock);
 713                        break;
 714                case OPN_ACPT:
 715                case CNF_ACPT:
 716                case OPN_RJCT:
 717                case CNF_RJCT:
 718                        llid = sta->llid;
 719                        reason = sta->reason;
 720                        spin_unlock_bh(&sta->lock);
 721                        mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr,
 722                                            llid, plid, reason);
 723                        break;
 724                default:
 725                        spin_unlock_bh(&sta->lock);
 726                }
 727                break;
 728        default:
 729                /* should not get here, PLINK_BLOCKED is dealt with at the
 730                 * beggining of the function
 731                 */
 732                spin_unlock_bh(&sta->lock);
 733                break;
 734        }
 735
 736        rcu_read_unlock();
 737}
 738