linux/net/wireless/ibss.c
<<
>>
Prefs
   1/*
   2 * Some IBSS support code for cfg80211.
   3 *
   4 * Copyright 2009       Johannes Berg <johannes@sipsolutions.net>
   5 */
   6
   7#include <linux/etherdevice.h>
   8#include <linux/if_arp.h>
   9#include <linux/slab.h>
  10#include <linux/export.h>
  11#include <net/cfg80211.h>
  12#include "wext-compat.h"
  13#include "nl80211.h"
  14#include "rdev-ops.h"
  15
  16
  17void __cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
  18                            struct ieee80211_channel *channel)
  19{
  20        struct wireless_dev *wdev = dev->ieee80211_ptr;
  21        struct cfg80211_bss *bss;
  22#ifdef CONFIG_CFG80211_WEXT
  23        union iwreq_data wrqu;
  24#endif
  25
  26        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
  27                return;
  28
  29        if (!wdev->ssid_len)
  30                return;
  31
  32        bss = cfg80211_get_bss(wdev->wiphy, channel, bssid, NULL, 0,
  33                               IEEE80211_BSS_TYPE_IBSS, IEEE80211_PRIVACY_ANY);
  34
  35        if (WARN_ON(!bss))
  36                return;
  37
  38        if (wdev->current_bss) {
  39                cfg80211_unhold_bss(wdev->current_bss);
  40                cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
  41        }
  42
  43        cfg80211_hold_bss(bss_from_pub(bss));
  44        wdev->current_bss = bss_from_pub(bss);
  45
  46        if (!(wdev->wiphy->flags & WIPHY_FLAG_HAS_STATIC_WEP))
  47                cfg80211_upload_connect_keys(wdev);
  48
  49        nl80211_send_ibss_bssid(wiphy_to_rdev(wdev->wiphy), dev, bssid,
  50                                GFP_KERNEL);
  51#ifdef CONFIG_CFG80211_WEXT
  52        memset(&wrqu, 0, sizeof(wrqu));
  53        memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
  54        wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
  55#endif
  56}
  57
  58void cfg80211_ibss_joined(struct net_device *dev, const u8 *bssid,
  59                          struct ieee80211_channel *channel, gfp_t gfp)
  60{
  61        struct wireless_dev *wdev = dev->ieee80211_ptr;
  62        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
  63        struct cfg80211_event *ev;
  64        unsigned long flags;
  65
  66        trace_cfg80211_ibss_joined(dev, bssid, channel);
  67
  68        if (WARN_ON(!channel))
  69                return;
  70
  71        ev = kzalloc(sizeof(*ev), gfp);
  72        if (!ev)
  73                return;
  74
  75        ev->type = EVENT_IBSS_JOINED;
  76        memcpy(ev->ij.bssid, bssid, ETH_ALEN);
  77        ev->ij.channel = channel;
  78
  79        spin_lock_irqsave(&wdev->event_lock, flags);
  80        list_add_tail(&ev->list, &wdev->event_list);
  81        spin_unlock_irqrestore(&wdev->event_lock, flags);
  82        queue_work(cfg80211_wq, &rdev->event_work);
  83}
  84EXPORT_SYMBOL(cfg80211_ibss_joined);
  85
  86static int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
  87                                struct net_device *dev,
  88                                struct cfg80211_ibss_params *params,
  89                                struct cfg80211_cached_keys *connkeys)
  90{
  91        struct wireless_dev *wdev = dev->ieee80211_ptr;
  92        int err;
  93
  94        ASSERT_WDEV_LOCK(wdev);
  95
  96        if (wdev->ssid_len)
  97                return -EALREADY;
  98
  99        if (!params->basic_rates) {
 100                /*
 101                * If no rates were explicitly configured,
 102                * use the mandatory rate set for 11b or
 103                * 11a for maximum compatibility.
 104                */
 105                struct ieee80211_supported_band *sband =
 106                        rdev->wiphy.bands[params->chandef.chan->band];
 107                int j;
 108                u32 flag = params->chandef.chan->band == NL80211_BAND_5GHZ ?
 109                        IEEE80211_RATE_MANDATORY_A :
 110                        IEEE80211_RATE_MANDATORY_B;
 111
 112                for (j = 0; j < sband->n_bitrates; j++) {
 113                        if (sband->bitrates[j].flags & flag)
 114                                params->basic_rates |= BIT(j);
 115                }
 116        }
 117
 118        if (WARN_ON(connkeys && connkeys->def < 0))
 119                return -EINVAL;
 120
 121        if (WARN_ON(wdev->connect_keys))
 122                kzfree(wdev->connect_keys);
 123        wdev->connect_keys = connkeys;
 124
 125        wdev->ibss_fixed = params->channel_fixed;
 126        wdev->ibss_dfs_possible = params->userspace_handles_dfs;
 127        wdev->chandef = params->chandef;
 128#ifdef CONFIG_CFG80211_WEXT
 129        wdev->wext.ibss.chandef = params->chandef;
 130#endif
 131        err = rdev_join_ibss(rdev, dev, params);
 132        if (err) {
 133                wdev->connect_keys = NULL;
 134                return err;
 135        }
 136
 137        memcpy(wdev->ssid, params->ssid, params->ssid_len);
 138        wdev->ssid_len = params->ssid_len;
 139
 140        return 0;
 141}
 142
 143int cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 144                       struct net_device *dev,
 145                       struct cfg80211_ibss_params *params,
 146                       struct cfg80211_cached_keys *connkeys)
 147{
 148        struct wireless_dev *wdev = dev->ieee80211_ptr;
 149        int err;
 150
 151        ASSERT_RTNL();
 152
 153        wdev_lock(wdev);
 154        err = __cfg80211_join_ibss(rdev, dev, params, connkeys);
 155        wdev_unlock(wdev);
 156
 157        return err;
 158}
 159
 160static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
 161{
 162        struct wireless_dev *wdev = dev->ieee80211_ptr;
 163        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
 164        int i;
 165
 166        ASSERT_WDEV_LOCK(wdev);
 167
 168        kzfree(wdev->connect_keys);
 169        wdev->connect_keys = NULL;
 170
 171        rdev_set_qos_map(rdev, dev, NULL);
 172
 173        /*
 174         * Delete all the keys ... pairwise keys can't really
 175         * exist any more anyway, but default keys might.
 176         */
 177        if (rdev->ops->del_key)
 178                for (i = 0; i < 6; i++)
 179                        rdev_del_key(rdev, dev, i, false, NULL);
 180
 181        if (wdev->current_bss) {
 182                cfg80211_unhold_bss(wdev->current_bss);
 183                cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
 184        }
 185
 186        wdev->current_bss = NULL;
 187        wdev->ssid_len = 0;
 188        memset(&wdev->chandef, 0, sizeof(wdev->chandef));
 189#ifdef CONFIG_CFG80211_WEXT
 190        if (!nowext)
 191                wdev->wext.ibss.ssid_len = 0;
 192#endif
 193}
 194
 195void cfg80211_clear_ibss(struct net_device *dev, bool nowext)
 196{
 197        struct wireless_dev *wdev = dev->ieee80211_ptr;
 198
 199        wdev_lock(wdev);
 200        __cfg80211_clear_ibss(dev, nowext);
 201        wdev_unlock(wdev);
 202}
 203
 204int __cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
 205                          struct net_device *dev, bool nowext)
 206{
 207        struct wireless_dev *wdev = dev->ieee80211_ptr;
 208        int err;
 209
 210        ASSERT_WDEV_LOCK(wdev);
 211
 212        if (!wdev->ssid_len)
 213                return -ENOLINK;
 214
 215        err = rdev_leave_ibss(rdev, dev);
 216
 217        if (err)
 218                return err;
 219
 220        __cfg80211_clear_ibss(dev, nowext);
 221
 222        return 0;
 223}
 224
 225int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
 226                        struct net_device *dev, bool nowext)
 227{
 228        struct wireless_dev *wdev = dev->ieee80211_ptr;
 229        int err;
 230
 231        wdev_lock(wdev);
 232        err = __cfg80211_leave_ibss(rdev, dev, nowext);
 233        wdev_unlock(wdev);
 234
 235        return err;
 236}
 237
 238#ifdef CONFIG_CFG80211_WEXT
 239int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
 240                            struct wireless_dev *wdev)
 241{
 242        struct cfg80211_cached_keys *ck = NULL;
 243        enum nl80211_band band;
 244        int i, err;
 245
 246        ASSERT_WDEV_LOCK(wdev);
 247
 248        if (!wdev->wext.ibss.beacon_interval)
 249                wdev->wext.ibss.beacon_interval = 100;
 250
 251        /* try to find an IBSS channel if none requested ... */
 252        if (!wdev->wext.ibss.chandef.chan) {
 253                struct ieee80211_channel *new_chan = NULL;
 254
 255                for (band = 0; band < NUM_NL80211_BANDS; band++) {
 256                        struct ieee80211_supported_band *sband;
 257                        struct ieee80211_channel *chan;
 258
 259                        sband = rdev->wiphy.bands[band];
 260                        if (!sband)
 261                                continue;
 262
 263                        for (i = 0; i < sband->n_channels; i++) {
 264                                chan = &sband->channels[i];
 265                                if (chan->flags & IEEE80211_CHAN_NO_IR)
 266                                        continue;
 267                                if (chan->flags & IEEE80211_CHAN_DISABLED)
 268                                        continue;
 269                                new_chan = chan;
 270                                break;
 271                        }
 272
 273                        if (new_chan)
 274                                break;
 275                }
 276
 277                if (!new_chan)
 278                        return -EINVAL;
 279
 280                cfg80211_chandef_create(&wdev->wext.ibss.chandef, new_chan,
 281                                        NL80211_CHAN_NO_HT);
 282        }
 283
 284        /* don't join -- SSID is not there */
 285        if (!wdev->wext.ibss.ssid_len)
 286                return 0;
 287
 288        if (!netif_running(wdev->netdev))
 289                return 0;
 290
 291        if (wdev->wext.keys)
 292                wdev->wext.keys->def = wdev->wext.default_key;
 293
 294        wdev->wext.ibss.privacy = wdev->wext.default_key != -1;
 295
 296        if (wdev->wext.keys && wdev->wext.keys->def != -1) {
 297                ck = kmemdup(wdev->wext.keys, sizeof(*ck), GFP_KERNEL);
 298                if (!ck)
 299                        return -ENOMEM;
 300                for (i = 0; i < CFG80211_MAX_WEP_KEYS; i++)
 301                        ck->params[i].key = ck->data[i];
 302        }
 303        err = __cfg80211_join_ibss(rdev, wdev->netdev,
 304                                   &wdev->wext.ibss, ck);
 305        if (err)
 306                kfree(ck);
 307
 308        return err;
 309}
 310
 311int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
 312                               struct iw_request_info *info,
 313                               struct iw_freq *wextfreq, char *extra)
 314{
 315        struct wireless_dev *wdev = dev->ieee80211_ptr;
 316        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
 317        struct ieee80211_channel *chan = NULL;
 318        int err, freq;
 319
 320        /* call only for ibss! */
 321        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
 322                return -EINVAL;
 323
 324        if (!rdev->ops->join_ibss)
 325                return -EOPNOTSUPP;
 326
 327        freq = cfg80211_wext_freq(wextfreq);
 328        if (freq < 0)
 329                return freq;
 330
 331        if (freq) {
 332                chan = ieee80211_get_channel(wdev->wiphy, freq);
 333                if (!chan)
 334                        return -EINVAL;
 335                if (chan->flags & IEEE80211_CHAN_NO_IR ||
 336                    chan->flags & IEEE80211_CHAN_DISABLED)
 337                        return -EINVAL;
 338        }
 339
 340        if (wdev->wext.ibss.chandef.chan == chan)
 341                return 0;
 342
 343        wdev_lock(wdev);
 344        err = 0;
 345        if (wdev->ssid_len)
 346                err = __cfg80211_leave_ibss(rdev, dev, true);
 347        wdev_unlock(wdev);
 348
 349        if (err)
 350                return err;
 351
 352        if (chan) {
 353                cfg80211_chandef_create(&wdev->wext.ibss.chandef, chan,
 354                                        NL80211_CHAN_NO_HT);
 355                wdev->wext.ibss.channel_fixed = true;
 356        } else {
 357                /* cfg80211_ibss_wext_join will pick one if needed */
 358                wdev->wext.ibss.channel_fixed = false;
 359        }
 360
 361        wdev_lock(wdev);
 362        err = cfg80211_ibss_wext_join(rdev, wdev);
 363        wdev_unlock(wdev);
 364
 365        return err;
 366}
 367
 368int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
 369                               struct iw_request_info *info,
 370                               struct iw_freq *freq, char *extra)
 371{
 372        struct wireless_dev *wdev = dev->ieee80211_ptr;
 373        struct ieee80211_channel *chan = NULL;
 374
 375        /* call only for ibss! */
 376        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
 377                return -EINVAL;
 378
 379        wdev_lock(wdev);
 380        if (wdev->current_bss)
 381                chan = wdev->current_bss->pub.channel;
 382        else if (wdev->wext.ibss.chandef.chan)
 383                chan = wdev->wext.ibss.chandef.chan;
 384        wdev_unlock(wdev);
 385
 386        if (chan) {
 387                freq->m = chan->center_freq;
 388                freq->e = 6;
 389                return 0;
 390        }
 391
 392        /* no channel if not joining */
 393        return -EINVAL;
 394}
 395
 396int cfg80211_ibss_wext_siwessid(struct net_device *dev,
 397                                struct iw_request_info *info,
 398                                struct iw_point *data, char *ssid)
 399{
 400        struct wireless_dev *wdev = dev->ieee80211_ptr;
 401        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
 402        size_t len = data->length;
 403        int err;
 404
 405        /* call only for ibss! */
 406        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
 407                return -EINVAL;
 408
 409        if (!rdev->ops->join_ibss)
 410                return -EOPNOTSUPP;
 411
 412        wdev_lock(wdev);
 413        err = 0;
 414        if (wdev->ssid_len)
 415                err = __cfg80211_leave_ibss(rdev, dev, true);
 416        wdev_unlock(wdev);
 417
 418        if (err)
 419                return err;
 420
 421        /* iwconfig uses nul termination in SSID.. */
 422        if (len > 0 && ssid[len - 1] == '\0')
 423                len--;
 424
 425        memcpy(wdev->ssid, ssid, len);
 426        wdev->wext.ibss.ssid = wdev->ssid;
 427        wdev->wext.ibss.ssid_len = len;
 428
 429        wdev_lock(wdev);
 430        err = cfg80211_ibss_wext_join(rdev, wdev);
 431        wdev_unlock(wdev);
 432
 433        return err;
 434}
 435
 436int cfg80211_ibss_wext_giwessid(struct net_device *dev,
 437                                struct iw_request_info *info,
 438                                struct iw_point *data, char *ssid)
 439{
 440        struct wireless_dev *wdev = dev->ieee80211_ptr;
 441
 442        /* call only for ibss! */
 443        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
 444                return -EINVAL;
 445
 446        data->flags = 0;
 447
 448        wdev_lock(wdev);
 449        if (wdev->ssid_len) {
 450                data->flags = 1;
 451                data->length = wdev->ssid_len;
 452                memcpy(ssid, wdev->ssid, data->length);
 453        } else if (wdev->wext.ibss.ssid && wdev->wext.ibss.ssid_len) {
 454                data->flags = 1;
 455                data->length = wdev->wext.ibss.ssid_len;
 456                memcpy(ssid, wdev->wext.ibss.ssid, data->length);
 457        }
 458        wdev_unlock(wdev);
 459
 460        return 0;
 461}
 462
 463int cfg80211_ibss_wext_siwap(struct net_device *dev,
 464                             struct iw_request_info *info,
 465                             struct sockaddr *ap_addr, char *extra)
 466{
 467        struct wireless_dev *wdev = dev->ieee80211_ptr;
 468        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy);
 469        u8 *bssid = ap_addr->sa_data;
 470        int err;
 471
 472        /* call only for ibss! */
 473        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
 474                return -EINVAL;
 475
 476        if (!rdev->ops->join_ibss)
 477                return -EOPNOTSUPP;
 478
 479        if (ap_addr->sa_family != ARPHRD_ETHER)
 480                return -EINVAL;
 481
 482        /* automatic mode */
 483        if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid))
 484                bssid = NULL;
 485
 486        if (bssid && !is_valid_ether_addr(bssid))
 487                return -EINVAL;
 488
 489        /* both automatic */
 490        if (!bssid && !wdev->wext.ibss.bssid)
 491                return 0;
 492
 493        /* fixed already - and no change */
 494        if (wdev->wext.ibss.bssid && bssid &&
 495            ether_addr_equal(bssid, wdev->wext.ibss.bssid))
 496                return 0;
 497
 498        wdev_lock(wdev);
 499        err = 0;
 500        if (wdev->ssid_len)
 501                err = __cfg80211_leave_ibss(rdev, dev, true);
 502        wdev_unlock(wdev);
 503
 504        if (err)
 505                return err;
 506
 507        if (bssid) {
 508                memcpy(wdev->wext.bssid, bssid, ETH_ALEN);
 509                wdev->wext.ibss.bssid = wdev->wext.bssid;
 510        } else
 511                wdev->wext.ibss.bssid = NULL;
 512
 513        wdev_lock(wdev);
 514        err = cfg80211_ibss_wext_join(rdev, wdev);
 515        wdev_unlock(wdev);
 516
 517        return err;
 518}
 519
 520int cfg80211_ibss_wext_giwap(struct net_device *dev,
 521                             struct iw_request_info *info,
 522                             struct sockaddr *ap_addr, char *extra)
 523{
 524        struct wireless_dev *wdev = dev->ieee80211_ptr;
 525
 526        /* call only for ibss! */
 527        if (WARN_ON(wdev->iftype != NL80211_IFTYPE_ADHOC))
 528                return -EINVAL;
 529
 530        ap_addr->sa_family = ARPHRD_ETHER;
 531
 532        wdev_lock(wdev);
 533        if (wdev->current_bss)
 534                memcpy(ap_addr->sa_data, wdev->current_bss->pub.bssid, ETH_ALEN);
 535        else if (wdev->wext.ibss.bssid)
 536                memcpy(ap_addr->sa_data, wdev->wext.ibss.bssid, ETH_ALEN);
 537        else
 538                eth_zero_addr(ap_addr->sa_data);
 539
 540        wdev_unlock(wdev);
 541
 542        return 0;
 543}
 544#endif
 545