linux/net/mac802154/cfg.c
<<
>>
Prefs
   1/* This program is free software; you can redistribute it and/or modify
   2 * it under the terms of the GNU General Public License version 2
   3 * as published by the Free Software Foundation.
   4 *
   5 * This program is distributed in the hope that it will be useful,
   6 * but WITHOUT ANY WARRANTY; without even the implied warranty of
   7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   8 * GNU General Public License for more details.
   9 *
  10 * Authors:
  11 * Alexander Aring <aar@pengutronix.de>
  12 *
  13 * Based on: net/mac80211/cfg.c
  14 */
  15
  16#include <net/rtnetlink.h>
  17#include <net/cfg802154.h>
  18
  19#include "ieee802154_i.h"
  20#include "driver-ops.h"
  21#include "cfg.h"
  22
  23static struct net_device *
  24ieee802154_add_iface_deprecated(struct wpan_phy *wpan_phy,
  25                                const char *name,
  26                                unsigned char name_assign_type, int type)
  27{
  28        struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
  29        struct net_device *dev;
  30
  31        rtnl_lock();
  32        dev = ieee802154_if_add(local, name, name_assign_type, type,
  33                                cpu_to_le64(0x0000000000000000ULL));
  34        rtnl_unlock();
  35
  36        return dev;
  37}
  38
  39static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy,
  40                                            struct net_device *dev)
  41{
  42        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
  43
  44        ieee802154_if_remove(sdata);
  45}
  46
  47#ifdef CONFIG_PM
  48static int ieee802154_suspend(struct wpan_phy *wpan_phy)
  49{
  50        struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
  51
  52        if (!local->open_count)
  53                goto suspend;
  54
  55        ieee802154_stop_queue(&local->hw);
  56        synchronize_net();
  57
  58        /* stop hardware - this must stop RX */
  59        ieee802154_stop_device(local);
  60
  61suspend:
  62        local->suspended = true;
  63        return 0;
  64}
  65
  66static int ieee802154_resume(struct wpan_phy *wpan_phy)
  67{
  68        struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
  69        int ret;
  70
  71        /* nothing to do if HW shouldn't run */
  72        if (!local->open_count)
  73                goto wake_up;
  74
  75        /* restart hardware */
  76        ret = drv_start(local);
  77        if (ret)
  78                return ret;
  79
  80wake_up:
  81        ieee802154_wake_queue(&local->hw);
  82        local->suspended = false;
  83        return 0;
  84}
  85#else
  86#define ieee802154_suspend NULL
  87#define ieee802154_resume NULL
  88#endif
  89
  90static int
  91ieee802154_add_iface(struct wpan_phy *phy, const char *name,
  92                     unsigned char name_assign_type,
  93                     enum nl802154_iftype type, __le64 extended_addr)
  94{
  95        struct ieee802154_local *local = wpan_phy_priv(phy);
  96        struct net_device *err;
  97
  98        err = ieee802154_if_add(local, name, name_assign_type, type,
  99                                extended_addr);
 100        return PTR_ERR_OR_ZERO(err);
 101}
 102
 103static int
 104ieee802154_del_iface(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev)
 105{
 106        ieee802154_if_remove(IEEE802154_WPAN_DEV_TO_SUB_IF(wpan_dev));
 107
 108        return 0;
 109}
 110
 111static int
 112ieee802154_set_channel(struct wpan_phy *wpan_phy, u8 page, u8 channel)
 113{
 114        struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
 115        int ret;
 116
 117        ASSERT_RTNL();
 118
 119        if (wpan_phy->current_page == page &&
 120            wpan_phy->current_channel == channel)
 121                return 0;
 122
 123        ret = drv_set_channel(local, page, channel);
 124        if (!ret) {
 125                wpan_phy->current_page = page;
 126                wpan_phy->current_channel = channel;
 127        }
 128
 129        return ret;
 130}
 131
 132static int
 133ieee802154_set_cca_mode(struct wpan_phy *wpan_phy,
 134                        const struct wpan_phy_cca *cca)
 135{
 136        struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
 137        int ret;
 138
 139        ASSERT_RTNL();
 140
 141        if (wpan_phy_cca_cmp(&wpan_phy->cca, cca))
 142                return 0;
 143
 144        ret = drv_set_cca_mode(local, cca);
 145        if (!ret)
 146                wpan_phy->cca = *cca;
 147
 148        return ret;
 149}
 150
 151static int
 152ieee802154_set_cca_ed_level(struct wpan_phy *wpan_phy, s32 ed_level)
 153{
 154        struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
 155        int ret;
 156
 157        ASSERT_RTNL();
 158
 159        if (wpan_phy->cca_ed_level == ed_level)
 160                return 0;
 161
 162        ret = drv_set_cca_ed_level(local, ed_level);
 163        if (!ret)
 164                wpan_phy->cca_ed_level = ed_level;
 165
 166        return ret;
 167}
 168
 169static int
 170ieee802154_set_tx_power(struct wpan_phy *wpan_phy, s32 power)
 171{
 172        struct ieee802154_local *local = wpan_phy_priv(wpan_phy);
 173        int ret;
 174
 175        ASSERT_RTNL();
 176
 177        if (wpan_phy->transmit_power == power)
 178                return 0;
 179
 180        ret = drv_set_tx_power(local, power);
 181        if (!ret)
 182                wpan_phy->transmit_power = power;
 183
 184        return ret;
 185}
 186
 187static int
 188ieee802154_set_pan_id(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
 189                      __le16 pan_id)
 190{
 191        int ret;
 192
 193        ASSERT_RTNL();
 194
 195        if (wpan_dev->pan_id == pan_id)
 196                return 0;
 197
 198        ret = mac802154_wpan_update_llsec(wpan_dev->netdev);
 199        if (!ret)
 200                wpan_dev->pan_id = pan_id;
 201
 202        return ret;
 203}
 204
 205static int
 206ieee802154_set_backoff_exponent(struct wpan_phy *wpan_phy,
 207                                struct wpan_dev *wpan_dev,
 208                                u8 min_be, u8 max_be)
 209{
 210        ASSERT_RTNL();
 211
 212        wpan_dev->min_be = min_be;
 213        wpan_dev->max_be = max_be;
 214        return 0;
 215}
 216
 217static int
 218ieee802154_set_short_addr(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
 219                          __le16 short_addr)
 220{
 221        ASSERT_RTNL();
 222
 223        wpan_dev->short_addr = short_addr;
 224        return 0;
 225}
 226
 227static int
 228ieee802154_set_max_csma_backoffs(struct wpan_phy *wpan_phy,
 229                                 struct wpan_dev *wpan_dev,
 230                                 u8 max_csma_backoffs)
 231{
 232        ASSERT_RTNL();
 233
 234        wpan_dev->csma_retries = max_csma_backoffs;
 235        return 0;
 236}
 237
 238static int
 239ieee802154_set_max_frame_retries(struct wpan_phy *wpan_phy,
 240                                 struct wpan_dev *wpan_dev,
 241                                 s8 max_frame_retries)
 242{
 243        ASSERT_RTNL();
 244
 245        wpan_dev->frame_retries = max_frame_retries;
 246        return 0;
 247}
 248
 249static int
 250ieee802154_set_lbt_mode(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
 251                        bool mode)
 252{
 253        ASSERT_RTNL();
 254
 255        wpan_dev->lbt = mode;
 256        return 0;
 257}
 258
 259static int
 260ieee802154_set_ackreq_default(struct wpan_phy *wpan_phy,
 261                              struct wpan_dev *wpan_dev, bool ackreq)
 262{
 263        ASSERT_RTNL();
 264
 265        wpan_dev->ackreq = ackreq;
 266        return 0;
 267}
 268
 269#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 270static void
 271ieee802154_get_llsec_table(struct wpan_phy *wpan_phy,
 272                           struct wpan_dev *wpan_dev,
 273                           struct ieee802154_llsec_table **table)
 274{
 275        struct net_device *dev = wpan_dev->netdev;
 276        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 277
 278        *table = &sdata->sec.table;
 279}
 280
 281static void
 282ieee802154_lock_llsec_table(struct wpan_phy *wpan_phy,
 283                            struct wpan_dev *wpan_dev)
 284{
 285        struct net_device *dev = wpan_dev->netdev;
 286        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 287
 288        mutex_lock(&sdata->sec_mtx);
 289}
 290
 291static void
 292ieee802154_unlock_llsec_table(struct wpan_phy *wpan_phy,
 293                              struct wpan_dev *wpan_dev)
 294{
 295        struct net_device *dev = wpan_dev->netdev;
 296        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 297
 298        mutex_unlock(&sdata->sec_mtx);
 299}
 300
 301static int
 302ieee802154_set_llsec_params(struct wpan_phy *wpan_phy,
 303                            struct wpan_dev *wpan_dev,
 304                            const struct ieee802154_llsec_params *params,
 305                            int changed)
 306{
 307        struct net_device *dev = wpan_dev->netdev;
 308        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 309        int res;
 310
 311        mutex_lock(&sdata->sec_mtx);
 312        res = mac802154_llsec_set_params(&sdata->sec, params, changed);
 313        mutex_unlock(&sdata->sec_mtx);
 314
 315        return res;
 316}
 317
 318static int
 319ieee802154_get_llsec_params(struct wpan_phy *wpan_phy,
 320                            struct wpan_dev *wpan_dev,
 321                            struct ieee802154_llsec_params *params)
 322{
 323        struct net_device *dev = wpan_dev->netdev;
 324        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 325        int res;
 326
 327        mutex_lock(&sdata->sec_mtx);
 328        res = mac802154_llsec_get_params(&sdata->sec, params);
 329        mutex_unlock(&sdata->sec_mtx);
 330
 331        return res;
 332}
 333
 334static int
 335ieee802154_add_llsec_key(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
 336                         const struct ieee802154_llsec_key_id *id,
 337                         const struct ieee802154_llsec_key *key)
 338{
 339        struct net_device *dev = wpan_dev->netdev;
 340        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 341        int res;
 342
 343        mutex_lock(&sdata->sec_mtx);
 344        res = mac802154_llsec_key_add(&sdata->sec, id, key);
 345        mutex_unlock(&sdata->sec_mtx);
 346
 347        return res;
 348}
 349
 350static int
 351ieee802154_del_llsec_key(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
 352                         const struct ieee802154_llsec_key_id *id)
 353{
 354        struct net_device *dev = wpan_dev->netdev;
 355        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 356        int res;
 357
 358        mutex_lock(&sdata->sec_mtx);
 359        res = mac802154_llsec_key_del(&sdata->sec, id);
 360        mutex_unlock(&sdata->sec_mtx);
 361
 362        return res;
 363}
 364
 365static int
 366ieee802154_add_seclevel(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
 367                        const struct ieee802154_llsec_seclevel *sl)
 368{
 369        struct net_device *dev = wpan_dev->netdev;
 370        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 371        int res;
 372
 373        mutex_lock(&sdata->sec_mtx);
 374        res = mac802154_llsec_seclevel_add(&sdata->sec, sl);
 375        mutex_unlock(&sdata->sec_mtx);
 376
 377        return res;
 378}
 379
 380static int
 381ieee802154_del_seclevel(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
 382                        const struct ieee802154_llsec_seclevel *sl)
 383{
 384        struct net_device *dev = wpan_dev->netdev;
 385        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 386        int res;
 387
 388        mutex_lock(&sdata->sec_mtx);
 389        res = mac802154_llsec_seclevel_del(&sdata->sec, sl);
 390        mutex_unlock(&sdata->sec_mtx);
 391
 392        return res;
 393}
 394
 395static int
 396ieee802154_add_device(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
 397                      const struct ieee802154_llsec_device *dev_desc)
 398{
 399        struct net_device *dev = wpan_dev->netdev;
 400        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 401        int res;
 402
 403        mutex_lock(&sdata->sec_mtx);
 404        res = mac802154_llsec_dev_add(&sdata->sec, dev_desc);
 405        mutex_unlock(&sdata->sec_mtx);
 406
 407        return res;
 408}
 409
 410static int
 411ieee802154_del_device(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
 412                      __le64 extended_addr)
 413{
 414        struct net_device *dev = wpan_dev->netdev;
 415        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 416        int res;
 417
 418        mutex_lock(&sdata->sec_mtx);
 419        res = mac802154_llsec_dev_del(&sdata->sec, extended_addr);
 420        mutex_unlock(&sdata->sec_mtx);
 421
 422        return res;
 423}
 424
 425static int
 426ieee802154_add_devkey(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
 427                      __le64 extended_addr,
 428                      const struct ieee802154_llsec_device_key *key)
 429{
 430        struct net_device *dev = wpan_dev->netdev;
 431        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 432        int res;
 433
 434        mutex_lock(&sdata->sec_mtx);
 435        res = mac802154_llsec_devkey_add(&sdata->sec, extended_addr, key);
 436        mutex_unlock(&sdata->sec_mtx);
 437
 438        return res;
 439}
 440
 441static int
 442ieee802154_del_devkey(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev,
 443                      __le64 extended_addr,
 444                      const struct ieee802154_llsec_device_key *key)
 445{
 446        struct net_device *dev = wpan_dev->netdev;
 447        struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev);
 448        int res;
 449
 450        mutex_lock(&sdata->sec_mtx);
 451        res = mac802154_llsec_devkey_del(&sdata->sec, extended_addr, key);
 452        mutex_unlock(&sdata->sec_mtx);
 453
 454        return res;
 455}
 456#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
 457
 458const struct cfg802154_ops mac802154_config_ops = {
 459        .add_virtual_intf_deprecated = ieee802154_add_iface_deprecated,
 460        .del_virtual_intf_deprecated = ieee802154_del_iface_deprecated,
 461        .suspend = ieee802154_suspend,
 462        .resume = ieee802154_resume,
 463        .add_virtual_intf = ieee802154_add_iface,
 464        .del_virtual_intf = ieee802154_del_iface,
 465        .set_channel = ieee802154_set_channel,
 466        .set_cca_mode = ieee802154_set_cca_mode,
 467        .set_cca_ed_level = ieee802154_set_cca_ed_level,
 468        .set_tx_power = ieee802154_set_tx_power,
 469        .set_pan_id = ieee802154_set_pan_id,
 470        .set_short_addr = ieee802154_set_short_addr,
 471        .set_backoff_exponent = ieee802154_set_backoff_exponent,
 472        .set_max_csma_backoffs = ieee802154_set_max_csma_backoffs,
 473        .set_max_frame_retries = ieee802154_set_max_frame_retries,
 474        .set_lbt_mode = ieee802154_set_lbt_mode,
 475        .set_ackreq_default = ieee802154_set_ackreq_default,
 476#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL
 477        .get_llsec_table = ieee802154_get_llsec_table,
 478        .lock_llsec_table = ieee802154_lock_llsec_table,
 479        .unlock_llsec_table = ieee802154_unlock_llsec_table,
 480        /* TODO above */
 481        .set_llsec_params = ieee802154_set_llsec_params,
 482        .get_llsec_params = ieee802154_get_llsec_params,
 483        .add_llsec_key = ieee802154_add_llsec_key,
 484        .del_llsec_key = ieee802154_del_llsec_key,
 485        .add_seclevel = ieee802154_add_seclevel,
 486        .del_seclevel = ieee802154_del_seclevel,
 487        .add_device = ieee802154_add_device,
 488        .del_device = ieee802154_del_device,
 489        .add_devkey = ieee802154_add_devkey,
 490        .del_devkey = ieee802154_del_devkey,
 491#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */
 492};
 493