linux/net/wireless/util.c
<<
>>
Prefs
   1/*
   2 * Wireless utility functions
   3 *
   4 * Copyright 2007-2009  Johannes Berg <johannes@sipsolutions.net>
   5 */
   6#include <linux/bitops.h>
   7#include <linux/etherdevice.h>
   8#include <net/cfg80211.h>
   9#include <net/ip.h>
  10#include "core.h"
  11
  12struct ieee80211_rate *
  13ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
  14                            u32 basic_rates, int bitrate)
  15{
  16        struct ieee80211_rate *result = &sband->bitrates[0];
  17        int i;
  18
  19        for (i = 0; i < sband->n_bitrates; i++) {
  20                if (!(basic_rates & BIT(i)))
  21                        continue;
  22                if (sband->bitrates[i].bitrate > bitrate)
  23                        continue;
  24                result = &sband->bitrates[i];
  25        }
  26
  27        return result;
  28}
  29EXPORT_SYMBOL(ieee80211_get_response_rate);
  30
  31int ieee80211_channel_to_frequency(int chan)
  32{
  33        if (chan < 14)
  34                return 2407 + chan * 5;
  35
  36        if (chan == 14)
  37                return 2484;
  38
  39        /* FIXME: 802.11j 17.3.8.3.2 */
  40        return (chan + 1000) * 5;
  41}
  42EXPORT_SYMBOL(ieee80211_channel_to_frequency);
  43
  44int ieee80211_frequency_to_channel(int freq)
  45{
  46        if (freq == 2484)
  47                return 14;
  48
  49        if (freq < 2484)
  50                return (freq - 2407) / 5;
  51
  52        /* FIXME: 802.11j 17.3.8.3.2 */
  53        return freq/5 - 1000;
  54}
  55EXPORT_SYMBOL(ieee80211_frequency_to_channel);
  56
  57struct ieee80211_channel *__ieee80211_get_channel(struct wiphy *wiphy,
  58                                                  int freq)
  59{
  60        enum ieee80211_band band;
  61        struct ieee80211_supported_band *sband;
  62        int i;
  63
  64        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
  65                sband = wiphy->bands[band];
  66
  67                if (!sband)
  68                        continue;
  69
  70                for (i = 0; i < sband->n_channels; i++) {
  71                        if (sband->channels[i].center_freq == freq)
  72                                return &sband->channels[i];
  73                }
  74        }
  75
  76        return NULL;
  77}
  78EXPORT_SYMBOL(__ieee80211_get_channel);
  79
  80static void set_mandatory_flags_band(struct ieee80211_supported_band *sband,
  81                                     enum ieee80211_band band)
  82{
  83        int i, want;
  84
  85        switch (band) {
  86        case IEEE80211_BAND_5GHZ:
  87                want = 3;
  88                for (i = 0; i < sband->n_bitrates; i++) {
  89                        if (sband->bitrates[i].bitrate == 60 ||
  90                            sband->bitrates[i].bitrate == 120 ||
  91                            sband->bitrates[i].bitrate == 240) {
  92                                sband->bitrates[i].flags |=
  93                                        IEEE80211_RATE_MANDATORY_A;
  94                                want--;
  95                        }
  96                }
  97                WARN_ON(want);
  98                break;
  99        case IEEE80211_BAND_2GHZ:
 100                want = 7;
 101                for (i = 0; i < sband->n_bitrates; i++) {
 102                        if (sband->bitrates[i].bitrate == 10) {
 103                                sband->bitrates[i].flags |=
 104                                        IEEE80211_RATE_MANDATORY_B |
 105                                        IEEE80211_RATE_MANDATORY_G;
 106                                want--;
 107                        }
 108
 109                        if (sband->bitrates[i].bitrate == 20 ||
 110                            sband->bitrates[i].bitrate == 55 ||
 111                            sband->bitrates[i].bitrate == 110 ||
 112                            sband->bitrates[i].bitrate == 60 ||
 113                            sband->bitrates[i].bitrate == 120 ||
 114                            sband->bitrates[i].bitrate == 240) {
 115                                sband->bitrates[i].flags |=
 116                                        IEEE80211_RATE_MANDATORY_G;
 117                                want--;
 118                        }
 119
 120                        if (sband->bitrates[i].bitrate != 10 &&
 121                            sband->bitrates[i].bitrate != 20 &&
 122                            sband->bitrates[i].bitrate != 55 &&
 123                            sband->bitrates[i].bitrate != 110)
 124                                sband->bitrates[i].flags |=
 125                                        IEEE80211_RATE_ERP_G;
 126                }
 127                WARN_ON(want != 0 && want != 3 && want != 6);
 128                break;
 129        case IEEE80211_NUM_BANDS:
 130                WARN_ON(1);
 131                break;
 132        }
 133}
 134
 135void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
 136{
 137        enum ieee80211_band band;
 138
 139        for (band = 0; band < IEEE80211_NUM_BANDS; band++)
 140                if (wiphy->bands[band])
 141                        set_mandatory_flags_band(wiphy->bands[band], band);
 142}
 143
 144int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
 145                                   struct key_params *params, int key_idx,
 146                                   const u8 *mac_addr)
 147{
 148        int i;
 149
 150        if (key_idx > 5)
 151                return -EINVAL;
 152
 153        /*
 154         * Disallow pairwise keys with non-zero index unless it's WEP
 155         * (because current deployments use pairwise WEP keys with
 156         * non-zero indizes but 802.11i clearly specifies to use zero)
 157         */
 158        if (mac_addr && key_idx &&
 159            params->cipher != WLAN_CIPHER_SUITE_WEP40 &&
 160            params->cipher != WLAN_CIPHER_SUITE_WEP104)
 161                return -EINVAL;
 162
 163        switch (params->cipher) {
 164        case WLAN_CIPHER_SUITE_WEP40:
 165                if (params->key_len != WLAN_KEY_LEN_WEP40)
 166                        return -EINVAL;
 167                break;
 168        case WLAN_CIPHER_SUITE_TKIP:
 169                if (params->key_len != WLAN_KEY_LEN_TKIP)
 170                        return -EINVAL;
 171                break;
 172        case WLAN_CIPHER_SUITE_CCMP:
 173                if (params->key_len != WLAN_KEY_LEN_CCMP)
 174                        return -EINVAL;
 175                break;
 176        case WLAN_CIPHER_SUITE_WEP104:
 177                if (params->key_len != WLAN_KEY_LEN_WEP104)
 178                        return -EINVAL;
 179                break;
 180        case WLAN_CIPHER_SUITE_AES_CMAC:
 181                if (params->key_len != WLAN_KEY_LEN_AES_CMAC)
 182                        return -EINVAL;
 183                break;
 184        default:
 185                return -EINVAL;
 186        }
 187
 188        if (params->seq) {
 189                switch (params->cipher) {
 190                case WLAN_CIPHER_SUITE_WEP40:
 191                case WLAN_CIPHER_SUITE_WEP104:
 192                        /* These ciphers do not use key sequence */
 193                        return -EINVAL;
 194                case WLAN_CIPHER_SUITE_TKIP:
 195                case WLAN_CIPHER_SUITE_CCMP:
 196                case WLAN_CIPHER_SUITE_AES_CMAC:
 197                        if (params->seq_len != 6)
 198                                return -EINVAL;
 199                        break;
 200                }
 201        }
 202
 203        for (i = 0; i < rdev->wiphy.n_cipher_suites; i++)
 204                if (params->cipher == rdev->wiphy.cipher_suites[i])
 205                        break;
 206        if (i == rdev->wiphy.n_cipher_suites)
 207                return -EINVAL;
 208
 209        return 0;
 210}
 211
 212/* See IEEE 802.1H for LLC/SNAP encapsulation/decapsulation */
 213/* Ethernet-II snap header (RFC1042 for most EtherTypes) */
 214const unsigned char rfc1042_header[] __aligned(2) =
 215        { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
 216EXPORT_SYMBOL(rfc1042_header);
 217
 218/* Bridge-Tunnel header (for EtherTypes ETH_P_AARP and ETH_P_IPX) */
 219const unsigned char bridge_tunnel_header[] __aligned(2) =
 220        { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
 221EXPORT_SYMBOL(bridge_tunnel_header);
 222
 223unsigned int ieee80211_hdrlen(__le16 fc)
 224{
 225        unsigned int hdrlen = 24;
 226
 227        if (ieee80211_is_data(fc)) {
 228                if (ieee80211_has_a4(fc))
 229                        hdrlen = 30;
 230                if (ieee80211_is_data_qos(fc))
 231                        hdrlen += IEEE80211_QOS_CTL_LEN;
 232                goto out;
 233        }
 234
 235        if (ieee80211_is_ctl(fc)) {
 236                /*
 237                 * ACK and CTS are 10 bytes, all others 16. To see how
 238                 * to get this condition consider
 239                 *   subtype mask:   0b0000000011110000 (0x00F0)
 240                 *   ACK subtype:    0b0000000011010000 (0x00D0)
 241                 *   CTS subtype:    0b0000000011000000 (0x00C0)
 242                 *   bits that matter:         ^^^      (0x00E0)
 243                 *   value of those: 0b0000000011000000 (0x00C0)
 244                 */
 245                if ((fc & cpu_to_le16(0x00E0)) == cpu_to_le16(0x00C0))
 246                        hdrlen = 10;
 247                else
 248                        hdrlen = 16;
 249        }
 250out:
 251        return hdrlen;
 252}
 253EXPORT_SYMBOL(ieee80211_hdrlen);
 254
 255unsigned int ieee80211_get_hdrlen_from_skb(const struct sk_buff *skb)
 256{
 257        const struct ieee80211_hdr *hdr =
 258                        (const struct ieee80211_hdr *)skb->data;
 259        unsigned int hdrlen;
 260
 261        if (unlikely(skb->len < 10))
 262                return 0;
 263        hdrlen = ieee80211_hdrlen(hdr->frame_control);
 264        if (unlikely(hdrlen > skb->len))
 265                return 0;
 266        return hdrlen;
 267}
 268EXPORT_SYMBOL(ieee80211_get_hdrlen_from_skb);
 269
 270static int ieee80211_get_mesh_hdrlen(struct ieee80211s_hdr *meshhdr)
 271{
 272        int ae = meshhdr->flags & MESH_FLAGS_AE;
 273        /* 7.1.3.5a.2 */
 274        switch (ae) {
 275        case 0:
 276                return 6;
 277        case MESH_FLAGS_AE_A4:
 278                return 12;
 279        case MESH_FLAGS_AE_A5_A6:
 280                return 18;
 281        case (MESH_FLAGS_AE_A4 | MESH_FLAGS_AE_A5_A6):
 282                return 24;
 283        default:
 284                return 6;
 285        }
 286}
 287
 288int ieee80211_data_to_8023(struct sk_buff *skb, u8 *addr,
 289                           enum nl80211_iftype iftype)
 290{
 291        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
 292        u16 hdrlen, ethertype;
 293        u8 *payload;
 294        u8 dst[ETH_ALEN];
 295        u8 src[ETH_ALEN] __aligned(2);
 296
 297        if (unlikely(!ieee80211_is_data_present(hdr->frame_control)))
 298                return -1;
 299
 300        hdrlen = ieee80211_hdrlen(hdr->frame_control);
 301
 302        /* convert IEEE 802.11 header + possible LLC headers into Ethernet
 303         * header
 304         * IEEE 802.11 address fields:
 305         * ToDS FromDS Addr1 Addr2 Addr3 Addr4
 306         *   0     0   DA    SA    BSSID n/a
 307         *   0     1   DA    BSSID SA    n/a
 308         *   1     0   BSSID SA    DA    n/a
 309         *   1     1   RA    TA    DA    SA
 310         */
 311        memcpy(dst, ieee80211_get_DA(hdr), ETH_ALEN);
 312        memcpy(src, ieee80211_get_SA(hdr), ETH_ALEN);
 313
 314        switch (hdr->frame_control &
 315                cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) {
 316        case cpu_to_le16(IEEE80211_FCTL_TODS):
 317                if (unlikely(iftype != NL80211_IFTYPE_AP &&
 318                             iftype != NL80211_IFTYPE_AP_VLAN))
 319                        return -1;
 320                break;
 321        case cpu_to_le16(IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS):
 322                if (unlikely(iftype != NL80211_IFTYPE_WDS &&
 323                             iftype != NL80211_IFTYPE_MESH_POINT))
 324                        return -1;
 325                if (iftype == NL80211_IFTYPE_MESH_POINT) {
 326                        struct ieee80211s_hdr *meshdr =
 327                                (struct ieee80211s_hdr *) (skb->data + hdrlen);
 328                        hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
 329                        if (meshdr->flags & MESH_FLAGS_AE_A5_A6) {
 330                                memcpy(dst, meshdr->eaddr1, ETH_ALEN);
 331                                memcpy(src, meshdr->eaddr2, ETH_ALEN);
 332                        }
 333                }
 334                break;
 335        case cpu_to_le16(IEEE80211_FCTL_FROMDS):
 336                if ((iftype != NL80211_IFTYPE_STATION &&
 337                    iftype != NL80211_IFTYPE_MESH_POINT) ||
 338                    (is_multicast_ether_addr(dst) &&
 339                     !compare_ether_addr(src, addr)))
 340                        return -1;
 341                if (iftype == NL80211_IFTYPE_MESH_POINT) {
 342                        struct ieee80211s_hdr *meshdr =
 343                                (struct ieee80211s_hdr *) (skb->data + hdrlen);
 344                        hdrlen += ieee80211_get_mesh_hdrlen(meshdr);
 345                        if (meshdr->flags & MESH_FLAGS_AE_A4)
 346                                memcpy(src, meshdr->eaddr1, ETH_ALEN);
 347                }
 348                break;
 349        case cpu_to_le16(0):
 350                if (iftype != NL80211_IFTYPE_ADHOC)
 351                        return -1;
 352                break;
 353        }
 354
 355        if (unlikely(skb->len - hdrlen < 8))
 356                return -1;
 357
 358        payload = skb->data + hdrlen;
 359        ethertype = (payload[6] << 8) | payload[7];
 360
 361        if (likely((compare_ether_addr(payload, rfc1042_header) == 0 &&
 362                    ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) ||
 363                   compare_ether_addr(payload, bridge_tunnel_header) == 0)) {
 364                /* remove RFC1042 or Bridge-Tunnel encapsulation and
 365                 * replace EtherType */
 366                skb_pull(skb, hdrlen + 6);
 367                memcpy(skb_push(skb, ETH_ALEN), src, ETH_ALEN);
 368                memcpy(skb_push(skb, ETH_ALEN), dst, ETH_ALEN);
 369        } else {
 370                struct ethhdr *ehdr;
 371                __be16 len;
 372
 373                skb_pull(skb, hdrlen);
 374                len = htons(skb->len);
 375                ehdr = (struct ethhdr *) skb_push(skb, sizeof(struct ethhdr));
 376                memcpy(ehdr->h_dest, dst, ETH_ALEN);
 377                memcpy(ehdr->h_source, src, ETH_ALEN);
 378                ehdr->h_proto = len;
 379        }
 380        return 0;
 381}
 382EXPORT_SYMBOL(ieee80211_data_to_8023);
 383
 384int ieee80211_data_from_8023(struct sk_buff *skb, u8 *addr,
 385                             enum nl80211_iftype iftype, u8 *bssid, bool qos)
 386{
 387        struct ieee80211_hdr hdr;
 388        u16 hdrlen, ethertype;
 389        __le16 fc;
 390        const u8 *encaps_data;
 391        int encaps_len, skip_header_bytes;
 392        int nh_pos, h_pos;
 393        int head_need;
 394
 395        if (unlikely(skb->len < ETH_HLEN))
 396                return -EINVAL;
 397
 398        nh_pos = skb_network_header(skb) - skb->data;
 399        h_pos = skb_transport_header(skb) - skb->data;
 400
 401        /* convert Ethernet header to proper 802.11 header (based on
 402         * operation mode) */
 403        ethertype = (skb->data[12] << 8) | skb->data[13];
 404        fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA);
 405
 406        switch (iftype) {
 407        case NL80211_IFTYPE_AP:
 408        case NL80211_IFTYPE_AP_VLAN:
 409                fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS);
 410                /* DA BSSID SA */
 411                memcpy(hdr.addr1, skb->data, ETH_ALEN);
 412                memcpy(hdr.addr2, addr, ETH_ALEN);
 413                memcpy(hdr.addr3, skb->data + ETH_ALEN, ETH_ALEN);
 414                hdrlen = 24;
 415                break;
 416        case NL80211_IFTYPE_STATION:
 417                fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
 418                /* BSSID SA DA */
 419                memcpy(hdr.addr1, bssid, ETH_ALEN);
 420                memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
 421                memcpy(hdr.addr3, skb->data, ETH_ALEN);
 422                hdrlen = 24;
 423                break;
 424        case NL80211_IFTYPE_ADHOC:
 425                /* DA SA BSSID */
 426                memcpy(hdr.addr1, skb->data, ETH_ALEN);
 427                memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
 428                memcpy(hdr.addr3, bssid, ETH_ALEN);
 429                hdrlen = 24;
 430                break;
 431        default:
 432                return -EOPNOTSUPP;
 433        }
 434
 435        if (qos) {
 436                fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
 437                hdrlen += 2;
 438        }
 439
 440        hdr.frame_control = fc;
 441        hdr.duration_id = 0;
 442        hdr.seq_ctrl = 0;
 443
 444        skip_header_bytes = ETH_HLEN;
 445        if (ethertype == ETH_P_AARP || ethertype == ETH_P_IPX) {
 446                encaps_data = bridge_tunnel_header;
 447                encaps_len = sizeof(bridge_tunnel_header);
 448                skip_header_bytes -= 2;
 449        } else if (ethertype > 0x600) {
 450                encaps_data = rfc1042_header;
 451                encaps_len = sizeof(rfc1042_header);
 452                skip_header_bytes -= 2;
 453        } else {
 454                encaps_data = NULL;
 455                encaps_len = 0;
 456        }
 457
 458        skb_pull(skb, skip_header_bytes);
 459        nh_pos -= skip_header_bytes;
 460        h_pos -= skip_header_bytes;
 461
 462        head_need = hdrlen + encaps_len - skb_headroom(skb);
 463
 464        if (head_need > 0 || skb_cloned(skb)) {
 465                head_need = max(head_need, 0);
 466                if (head_need)
 467                        skb_orphan(skb);
 468
 469                if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) {
 470                        printk(KERN_ERR "failed to reallocate Tx buffer\n");
 471                        return -ENOMEM;
 472                }
 473                skb->truesize += head_need;
 474        }
 475
 476        if (encaps_data) {
 477                memcpy(skb_push(skb, encaps_len), encaps_data, encaps_len);
 478                nh_pos += encaps_len;
 479                h_pos += encaps_len;
 480        }
 481
 482        memcpy(skb_push(skb, hdrlen), &hdr, hdrlen);
 483
 484        nh_pos += hdrlen;
 485        h_pos += hdrlen;
 486
 487        /* Update skb pointers to various headers since this modified frame
 488         * is going to go through Linux networking code that may potentially
 489         * need things like pointer to IP header. */
 490        skb_set_mac_header(skb, 0);
 491        skb_set_network_header(skb, nh_pos);
 492        skb_set_transport_header(skb, h_pos);
 493
 494        return 0;
 495}
 496EXPORT_SYMBOL(ieee80211_data_from_8023);
 497
 498/* Given a data frame determine the 802.1p/1d tag to use. */
 499unsigned int cfg80211_classify8021d(struct sk_buff *skb)
 500{
 501        unsigned int dscp;
 502
 503        /* skb->priority values from 256->263 are magic values to
 504         * directly indicate a specific 802.1d priority.  This is used
 505         * to allow 802.1d priority to be passed directly in from VLAN
 506         * tags, etc.
 507         */
 508        if (skb->priority >= 256 && skb->priority <= 263)
 509                return skb->priority - 256;
 510
 511        switch (skb->protocol) {
 512        case htons(ETH_P_IP):
 513                dscp = ip_hdr(skb)->tos & 0xfc;
 514                break;
 515        default:
 516                return 0;
 517        }
 518
 519        return dscp >> 5;
 520}
 521EXPORT_SYMBOL(cfg80211_classify8021d);
 522
 523const u8 *ieee80211_bss_get_ie(struct cfg80211_bss *bss, u8 ie)
 524{
 525        u8 *end, *pos;
 526
 527        pos = bss->information_elements;
 528        if (pos == NULL)
 529                return NULL;
 530        end = pos + bss->len_information_elements;
 531
 532        while (pos + 1 < end) {
 533                if (pos + 2 + pos[1] > end)
 534                        break;
 535                if (pos[0] == ie)
 536                        return pos;
 537                pos += 2 + pos[1];
 538        }
 539
 540        return NULL;
 541}
 542EXPORT_SYMBOL(ieee80211_bss_get_ie);
 543
 544void cfg80211_upload_connect_keys(struct wireless_dev *wdev)
 545{
 546        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
 547        struct net_device *dev = wdev->netdev;
 548        int i;
 549
 550        if (!wdev->connect_keys)
 551                return;
 552
 553        for (i = 0; i < 6; i++) {
 554                if (!wdev->connect_keys->params[i].cipher)
 555                        continue;
 556                if (rdev->ops->add_key(wdev->wiphy, dev, i, NULL,
 557                                        &wdev->connect_keys->params[i])) {
 558                        printk(KERN_ERR "%s: failed to set key %d\n",
 559                                dev->name, i);
 560                        continue;
 561                }
 562                if (wdev->connect_keys->def == i)
 563                        if (rdev->ops->set_default_key(wdev->wiphy, dev, i)) {
 564                                printk(KERN_ERR "%s: failed to set defkey %d\n",
 565                                        dev->name, i);
 566                                continue;
 567                        }
 568                if (wdev->connect_keys->defmgmt == i)
 569                        if (rdev->ops->set_default_mgmt_key(wdev->wiphy, dev, i))
 570                                printk(KERN_ERR "%s: failed to set mgtdef %d\n",
 571                                        dev->name, i);
 572        }
 573
 574        kfree(wdev->connect_keys);
 575        wdev->connect_keys = NULL;
 576}
 577
 578static void cfg80211_process_wdev_events(struct wireless_dev *wdev)
 579{
 580        struct cfg80211_event *ev;
 581        unsigned long flags;
 582        const u8 *bssid = NULL;
 583
 584        spin_lock_irqsave(&wdev->event_lock, flags);
 585        while (!list_empty(&wdev->event_list)) {
 586                ev = list_first_entry(&wdev->event_list,
 587                                      struct cfg80211_event, list);
 588                list_del(&ev->list);
 589                spin_unlock_irqrestore(&wdev->event_lock, flags);
 590
 591                wdev_lock(wdev);
 592                switch (ev->type) {
 593                case EVENT_CONNECT_RESULT:
 594                        if (!is_zero_ether_addr(ev->cr.bssid))
 595                                bssid = ev->cr.bssid;
 596                        __cfg80211_connect_result(
 597                                wdev->netdev, bssid,
 598                                ev->cr.req_ie, ev->cr.req_ie_len,
 599                                ev->cr.resp_ie, ev->cr.resp_ie_len,
 600                                ev->cr.status,
 601                                ev->cr.status == WLAN_STATUS_SUCCESS,
 602                                NULL);
 603                        break;
 604                case EVENT_ROAMED:
 605                        __cfg80211_roamed(wdev, ev->rm.bssid,
 606                                          ev->rm.req_ie, ev->rm.req_ie_len,
 607                                          ev->rm.resp_ie, ev->rm.resp_ie_len);
 608                        break;
 609                case EVENT_DISCONNECTED:
 610                        __cfg80211_disconnected(wdev->netdev,
 611                                                ev->dc.ie, ev->dc.ie_len,
 612                                                ev->dc.reason, true);
 613                        break;
 614                case EVENT_IBSS_JOINED:
 615                        __cfg80211_ibss_joined(wdev->netdev, ev->ij.bssid);
 616                        break;
 617                }
 618                wdev_unlock(wdev);
 619
 620                kfree(ev);
 621
 622                spin_lock_irqsave(&wdev->event_lock, flags);
 623        }
 624        spin_unlock_irqrestore(&wdev->event_lock, flags);
 625}
 626
 627void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev)
 628{
 629        struct wireless_dev *wdev;
 630
 631        ASSERT_RTNL();
 632        ASSERT_RDEV_LOCK(rdev);
 633
 634        mutex_lock(&rdev->devlist_mtx);
 635
 636        list_for_each_entry(wdev, &rdev->netdev_list, list)
 637                cfg80211_process_wdev_events(wdev);
 638
 639        mutex_unlock(&rdev->devlist_mtx);
 640}
 641
 642int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 643                          struct net_device *dev, enum nl80211_iftype ntype,
 644                          u32 *flags, struct vif_params *params)
 645{
 646        int err;
 647        enum nl80211_iftype otype = dev->ieee80211_ptr->iftype;
 648
 649        ASSERT_RDEV_LOCK(rdev);
 650
 651        /* don't support changing VLANs, you just re-create them */
 652        if (otype == NL80211_IFTYPE_AP_VLAN)
 653                return -EOPNOTSUPP;
 654
 655        if (!rdev->ops->change_virtual_intf ||
 656            !(rdev->wiphy.interface_modes & (1 << ntype)))
 657                return -EOPNOTSUPP;
 658
 659        if (ntype != otype) {
 660                switch (otype) {
 661                case NL80211_IFTYPE_ADHOC:
 662                        cfg80211_leave_ibss(rdev, dev, false);
 663                        break;
 664                case NL80211_IFTYPE_STATION:
 665                        cfg80211_disconnect(rdev, dev,
 666                                            WLAN_REASON_DEAUTH_LEAVING, true);
 667                        break;
 668                case NL80211_IFTYPE_MESH_POINT:
 669                        /* mesh should be handled? */
 670                        break;
 671                default:
 672                        break;
 673                }
 674
 675                cfg80211_process_rdev_events(rdev);
 676        }
 677
 678        err = rdev->ops->change_virtual_intf(&rdev->wiphy, dev,
 679                                             ntype, flags, params);
 680
 681        WARN_ON(!err && dev->ieee80211_ptr->iftype != ntype);
 682
 683        return err;
 684}
 685