linux/net/wimax/stack.c
<<
>>
Prefs
   1/*
   2 * Linux WiMAX
   3 * Initialization, addition and removal of wimax devices
   4 *
   5 *
   6 * Copyright (C) 2005-2006 Intel Corporation <linux-wimax@intel.com>
   7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
   8 *
   9 * This program is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU General Public License version
  11 * 2 as published by the Free Software Foundation.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  21 * 02110-1301, USA.
  22 *
  23 *
  24 * This implements:
  25 *
  26 *   - basic life cycle of 'struct wimax_dev' [wimax_dev_*()]; on
  27 *     addition/registration initialize all subfields and allocate
  28 *     generic netlink resources for user space communication. On
  29 *     removal/unregistration, undo all that.
  30 *
  31 *   - device state machine [wimax_state_change()] and support to send
  32 *     reports to user space when the state changes
  33 *     [wimax_gnl_re_state_change*()].
  34 *
  35 * See include/net/wimax.h for rationales and design.
  36 *
  37 * ROADMAP
  38 *
  39 * [__]wimax_state_change()     Called by drivers to update device's state
  40 *   wimax_gnl_re_state_change_alloc()
  41 *   wimax_gnl_re_state_change_send()
  42 *
  43 * wimax_dev_init()             Init a device
  44 * wimax_dev_add()              Register
  45 *   wimax_rfkill_add()
  46 *   wimax_gnl_add()            Register all the generic netlink resources.
  47 *   wimax_id_table_add()
  48 * wimax_dev_rm()               Unregister
  49 *   wimax_id_table_rm()
  50 *   wimax_gnl_rm()
  51 *   wimax_rfkill_rm()
  52 */
  53#include <linux/device.h>
  54#include <linux/gfp.h>
  55#include <net/genetlink.h>
  56#include <linux/netdevice.h>
  57#include <linux/wimax.h>
  58#include <linux/module.h>
  59#include "wimax-internal.h"
  60
  61
  62#define D_SUBMODULE stack
  63#include "debug-levels.h"
  64
  65static char wimax_debug_params[128];
  66module_param_string(debug, wimax_debug_params, sizeof(wimax_debug_params),
  67                    0644);
  68MODULE_PARM_DESC(debug,
  69                 "String of space-separated NAME:VALUE pairs, where NAMEs "
  70                 "are the different debug submodules and VALUE are the "
  71                 "initial debug value to set.");
  72
  73/*
  74 * Authoritative source for the RE_STATE_CHANGE attribute policy
  75 *
  76 * We don't really use it here, but /me likes to keep the definition
  77 * close to where the data is generated.
  78 */
  79/*
  80static const struct nla_policy wimax_gnl_re_status_change[WIMAX_GNL_ATTR_MAX + 1] = {
  81        [WIMAX_GNL_STCH_STATE_OLD] = { .type = NLA_U8 },
  82        [WIMAX_GNL_STCH_STATE_NEW] = { .type = NLA_U8 },
  83};
  84*/
  85
  86
  87/*
  88 * Allocate a Report State Change message
  89 *
  90 * @header: save it, you need it for _send()
  91 *
  92 * Creates and fills a basic state change message; different code
  93 * paths can then add more attributes to the message as needed.
  94 *
  95 * Use wimax_gnl_re_state_change_send() to send the returned skb.
  96 *
  97 * Returns: skb with the genl message if ok, IS_ERR() ptr on error
  98 *     with an errno code.
  99 */
 100static
 101struct sk_buff *wimax_gnl_re_state_change_alloc(
 102        struct wimax_dev *wimax_dev,
 103        enum wimax_st new_state, enum wimax_st old_state,
 104        void **header)
 105{
 106        int result;
 107        struct device *dev = wimax_dev_to_dev(wimax_dev);
 108        void *data;
 109        struct sk_buff *report_skb;
 110
 111        d_fnstart(3, dev, "(wimax_dev %p new_state %u old_state %u)\n",
 112                  wimax_dev, new_state, old_state);
 113        result = -ENOMEM;
 114        report_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
 115        if (report_skb == NULL) {
 116                dev_err(dev, "RE_STCH: can't create message\n");
 117                goto error_new;
 118        }
 119        /* FIXME: sending a group ID as the seq is wrong */
 120        data = genlmsg_put(report_skb, 0, wimax_gnl_family.mcgrp_offset,
 121                           &wimax_gnl_family, 0, WIMAX_GNL_RE_STATE_CHANGE);
 122        if (data == NULL) {
 123                dev_err(dev, "RE_STCH: can't put data into message\n");
 124                goto error_put;
 125        }
 126        *header = data;
 127
 128        result = nla_put_u8(report_skb, WIMAX_GNL_STCH_STATE_OLD, old_state);
 129        if (result < 0) {
 130                dev_err(dev, "RE_STCH: Error adding OLD attr: %d\n", result);
 131                goto error_put;
 132        }
 133        result = nla_put_u8(report_skb, WIMAX_GNL_STCH_STATE_NEW, new_state);
 134        if (result < 0) {
 135                dev_err(dev, "RE_STCH: Error adding NEW attr: %d\n", result);
 136                goto error_put;
 137        }
 138        result = nla_put_u32(report_skb, WIMAX_GNL_STCH_IFIDX,
 139                             wimax_dev->net_dev->ifindex);
 140        if (result < 0) {
 141                dev_err(dev, "RE_STCH: Error adding IFINDEX attribute\n");
 142                goto error_put;
 143        }
 144        d_fnend(3, dev, "(wimax_dev %p new_state %u old_state %u) = %p\n",
 145                wimax_dev, new_state, old_state, report_skb);
 146        return report_skb;
 147
 148error_put:
 149        nlmsg_free(report_skb);
 150error_new:
 151        d_fnend(3, dev, "(wimax_dev %p new_state %u old_state %u) = %d\n",
 152                wimax_dev, new_state, old_state, result);
 153        return ERR_PTR(result);
 154}
 155
 156
 157/*
 158 * Send a Report State Change message (as created with _alloc).
 159 *
 160 * @report_skb: as returned by wimax_gnl_re_state_change_alloc()
 161 * @header: as returned by wimax_gnl_re_state_change_alloc()
 162 *
 163 * Returns: 0 if ok, < 0 errno code on error.
 164 *
 165 * If the message is  NULL, pretend it didn't happen.
 166 */
 167static
 168int wimax_gnl_re_state_change_send(
 169        struct wimax_dev *wimax_dev, struct sk_buff *report_skb,
 170        void *header)
 171{
 172        int result = 0;
 173        struct device *dev = wimax_dev_to_dev(wimax_dev);
 174        d_fnstart(3, dev, "(wimax_dev %p report_skb %p)\n",
 175                  wimax_dev, report_skb);
 176        if (report_skb == NULL) {
 177                result = -ENOMEM;
 178                goto out;
 179        }
 180        genlmsg_end(report_skb, header);
 181        genlmsg_multicast(&wimax_gnl_family, report_skb, 0, 0, GFP_KERNEL);
 182out:
 183        d_fnend(3, dev, "(wimax_dev %p report_skb %p) = %d\n",
 184                wimax_dev, report_skb, result);
 185        return result;
 186}
 187
 188
 189static
 190void __check_new_state(enum wimax_st old_state, enum wimax_st new_state,
 191                       unsigned int allowed_states_bm)
 192{
 193        if (WARN_ON(((1 << new_state) & allowed_states_bm) == 0)) {
 194                pr_err("SW BUG! Forbidden state change %u -> %u\n",
 195                       old_state, new_state);
 196        }
 197}
 198
 199
 200/*
 201 * Set the current state of a WiMAX device [unlocking version of
 202 * wimax_state_change().
 203 */
 204void __wimax_state_change(struct wimax_dev *wimax_dev, enum wimax_st new_state)
 205{
 206        struct device *dev = wimax_dev_to_dev(wimax_dev);
 207        enum wimax_st old_state = wimax_dev->state;
 208        struct sk_buff *stch_skb;
 209        void *header;
 210
 211        d_fnstart(3, dev, "(wimax_dev %p new_state %u [old %u])\n",
 212                  wimax_dev, new_state, old_state);
 213
 214        if (WARN_ON(new_state >= __WIMAX_ST_INVALID)) {
 215                dev_err(dev, "SW BUG: requesting invalid state %u\n",
 216                        new_state);
 217                goto out;
 218        }
 219        if (old_state == new_state)
 220                goto out;
 221        header = NULL;  /* gcc complains? can't grok why */
 222        stch_skb = wimax_gnl_re_state_change_alloc(
 223                wimax_dev, new_state, old_state, &header);
 224
 225        /* Verify the state transition and do exit-from-state actions */
 226        switch (old_state) {
 227        case __WIMAX_ST_NULL:
 228                __check_new_state(old_state, new_state,
 229                                  1 << WIMAX_ST_DOWN);
 230                break;
 231        case WIMAX_ST_DOWN:
 232                __check_new_state(old_state, new_state,
 233                                  1 << __WIMAX_ST_QUIESCING
 234                                  | 1 << WIMAX_ST_UNINITIALIZED
 235                                  | 1 << WIMAX_ST_RADIO_OFF);
 236                break;
 237        case __WIMAX_ST_QUIESCING:
 238                __check_new_state(old_state, new_state, 1 << WIMAX_ST_DOWN);
 239                break;
 240        case WIMAX_ST_UNINITIALIZED:
 241                __check_new_state(old_state, new_state,
 242                                  1 << __WIMAX_ST_QUIESCING
 243                                  | 1 << WIMAX_ST_RADIO_OFF);
 244                break;
 245        case WIMAX_ST_RADIO_OFF:
 246                __check_new_state(old_state, new_state,
 247                                  1 << __WIMAX_ST_QUIESCING
 248                                  | 1 << WIMAX_ST_READY);
 249                break;
 250        case WIMAX_ST_READY:
 251                __check_new_state(old_state, new_state,
 252                                  1 << __WIMAX_ST_QUIESCING
 253                                  | 1 << WIMAX_ST_RADIO_OFF
 254                                  | 1 << WIMAX_ST_SCANNING
 255                                  | 1 << WIMAX_ST_CONNECTING
 256                                  | 1 << WIMAX_ST_CONNECTED);
 257                break;
 258        case WIMAX_ST_SCANNING:
 259                __check_new_state(old_state, new_state,
 260                                  1 << __WIMAX_ST_QUIESCING
 261                                  | 1 << WIMAX_ST_RADIO_OFF
 262                                  | 1 << WIMAX_ST_READY
 263                                  | 1 << WIMAX_ST_CONNECTING
 264                                  | 1 << WIMAX_ST_CONNECTED);
 265                break;
 266        case WIMAX_ST_CONNECTING:
 267                __check_new_state(old_state, new_state,
 268                                  1 << __WIMAX_ST_QUIESCING
 269                                  | 1 << WIMAX_ST_RADIO_OFF
 270                                  | 1 << WIMAX_ST_READY
 271                                  | 1 << WIMAX_ST_SCANNING
 272                                  | 1 << WIMAX_ST_CONNECTED);
 273                break;
 274        case WIMAX_ST_CONNECTED:
 275                __check_new_state(old_state, new_state,
 276                                  1 << __WIMAX_ST_QUIESCING
 277                                  | 1 << WIMAX_ST_RADIO_OFF
 278                                  | 1 << WIMAX_ST_READY);
 279                netif_tx_disable(wimax_dev->net_dev);
 280                netif_carrier_off(wimax_dev->net_dev);
 281                break;
 282        case __WIMAX_ST_INVALID:
 283        default:
 284                dev_err(dev, "SW BUG: wimax_dev %p is in unknown state %u\n",
 285                        wimax_dev, wimax_dev->state);
 286                WARN_ON(1);
 287                goto out;
 288        }
 289
 290        /* Execute the actions of entry to the new state */
 291        switch (new_state) {
 292        case __WIMAX_ST_NULL:
 293                dev_err(dev, "SW BUG: wimax_dev %p entering NULL state "
 294                        "from %u\n", wimax_dev, wimax_dev->state);
 295                WARN_ON(1);             /* Nobody can enter this state */
 296                break;
 297        case WIMAX_ST_DOWN:
 298                break;
 299        case __WIMAX_ST_QUIESCING:
 300                break;
 301        case WIMAX_ST_UNINITIALIZED:
 302                break;
 303        case WIMAX_ST_RADIO_OFF:
 304                break;
 305        case WIMAX_ST_READY:
 306                break;
 307        case WIMAX_ST_SCANNING:
 308                break;
 309        case WIMAX_ST_CONNECTING:
 310                break;
 311        case WIMAX_ST_CONNECTED:
 312                netif_carrier_on(wimax_dev->net_dev);
 313                netif_wake_queue(wimax_dev->net_dev);
 314                break;
 315        case __WIMAX_ST_INVALID:
 316        default:
 317                BUG();
 318        }
 319        __wimax_state_set(wimax_dev, new_state);
 320        if (!IS_ERR(stch_skb))
 321                wimax_gnl_re_state_change_send(wimax_dev, stch_skb, header);
 322out:
 323        d_fnend(3, dev, "(wimax_dev %p new_state %u [old %u]) = void\n",
 324                wimax_dev, new_state, old_state);
 325}
 326
 327
 328/**
 329 * wimax_state_change - Set the current state of a WiMAX device
 330 *
 331 * @wimax_dev: WiMAX device descriptor (properly referenced)
 332 * @new_state: New state to switch to
 333 *
 334 * This implements the state changes for the wimax devices. It will
 335 *
 336 * - verify that the state transition is legal (for now it'll just
 337 *   print a warning if not) according to the table in
 338 *   linux/wimax.h's documentation for 'enum wimax_st'.
 339 *
 340 * - perform the actions needed for leaving the current state and
 341 *   whichever are needed for entering the new state.
 342 *
 343 * - issue a report to user space indicating the new state (and an
 344 *   optional payload with information about the new state).
 345 *
 346 * NOTE: @wimax_dev must be locked
 347 */
 348void wimax_state_change(struct wimax_dev *wimax_dev, enum wimax_st new_state)
 349{
 350        /*
 351         * A driver cannot take the wimax_dev out of the
 352         * __WIMAX_ST_NULL state unless by calling wimax_dev_add(). If
 353         * the wimax_dev's state is still NULL, we ignore any request
 354         * to change its state because it means it hasn't been yet
 355         * registered.
 356         *
 357         * There is no need to complain about it, as routines that
 358         * call this might be shared from different code paths that
 359         * are called before or after wimax_dev_add() has done its
 360         * job.
 361         */
 362        mutex_lock(&wimax_dev->mutex);
 363        if (wimax_dev->state > __WIMAX_ST_NULL)
 364                __wimax_state_change(wimax_dev, new_state);
 365        mutex_unlock(&wimax_dev->mutex);
 366}
 367EXPORT_SYMBOL_GPL(wimax_state_change);
 368
 369
 370/**
 371 * wimax_state_get() - Return the current state of a WiMAX device
 372 *
 373 * @wimax_dev: WiMAX device descriptor
 374 *
 375 * Returns: Current state of the device according to its driver.
 376 */
 377enum wimax_st wimax_state_get(struct wimax_dev *wimax_dev)
 378{
 379        enum wimax_st state;
 380        mutex_lock(&wimax_dev->mutex);
 381        state = wimax_dev->state;
 382        mutex_unlock(&wimax_dev->mutex);
 383        return state;
 384}
 385EXPORT_SYMBOL_GPL(wimax_state_get);
 386
 387
 388/**
 389 * wimax_dev_init - initialize a newly allocated instance
 390 *
 391 * @wimax_dev: WiMAX device descriptor to initialize.
 392 *
 393 * Initializes fields of a freshly allocated @wimax_dev instance. This
 394 * function assumes that after allocation, the memory occupied by
 395 * @wimax_dev was zeroed.
 396 */
 397void wimax_dev_init(struct wimax_dev *wimax_dev)
 398{
 399        INIT_LIST_HEAD(&wimax_dev->id_table_node);
 400        __wimax_state_set(wimax_dev, __WIMAX_ST_NULL);
 401        mutex_init(&wimax_dev->mutex);
 402        mutex_init(&wimax_dev->mutex_reset);
 403}
 404EXPORT_SYMBOL_GPL(wimax_dev_init);
 405
 406static const struct nla_policy wimax_gnl_policy[WIMAX_GNL_ATTR_MAX + 1] = {
 407        [WIMAX_GNL_RESET_IFIDX] = { .type = NLA_U32, },
 408        [WIMAX_GNL_RFKILL_IFIDX] = { .type = NLA_U32, },
 409        [WIMAX_GNL_RFKILL_STATE] = {
 410                .type = NLA_U32         /* enum wimax_rf_state */
 411        },
 412        [WIMAX_GNL_STGET_IFIDX] = { .type = NLA_U32, },
 413        [WIMAX_GNL_MSG_IFIDX] = { .type = NLA_U32, },
 414        [WIMAX_GNL_MSG_DATA] = {
 415                .type = NLA_UNSPEC,     /* libnl doesn't grok BINARY yet */
 416        },
 417};
 418
 419static const struct genl_ops wimax_gnl_ops[] = {
 420        {
 421                .cmd = WIMAX_GNL_OP_MSG_FROM_USER,
 422                .flags = GENL_ADMIN_PERM,
 423                .policy = wimax_gnl_policy,
 424                .doit = wimax_gnl_doit_msg_from_user,
 425        },
 426        {
 427                .cmd = WIMAX_GNL_OP_RESET,
 428                .flags = GENL_ADMIN_PERM,
 429                .policy = wimax_gnl_policy,
 430                .doit = wimax_gnl_doit_reset,
 431        },
 432        {
 433                .cmd = WIMAX_GNL_OP_RFKILL,
 434                .flags = GENL_ADMIN_PERM,
 435                .policy = wimax_gnl_policy,
 436                .doit = wimax_gnl_doit_rfkill,
 437        },
 438        {
 439                .cmd = WIMAX_GNL_OP_STATE_GET,
 440                .flags = GENL_ADMIN_PERM,
 441                .policy = wimax_gnl_policy,
 442                .doit = wimax_gnl_doit_state_get,
 443        },
 444};
 445
 446
 447static
 448size_t wimax_addr_scnprint(char *addr_str, size_t addr_str_size,
 449                           unsigned char *addr, size_t addr_len)
 450{
 451        unsigned int cnt, total;
 452
 453        for (total = cnt = 0; cnt < addr_len; cnt++)
 454                total += scnprintf(addr_str + total, addr_str_size - total,
 455                                   "%02x%c", addr[cnt],
 456                                   cnt == addr_len - 1 ? '\0' : ':');
 457        return total;
 458}
 459
 460
 461/**
 462 * wimax_dev_add - Register a new WiMAX device
 463 *
 464 * @wimax_dev: WiMAX device descriptor (as embedded in your @net_dev's
 465 *     priv data). You must have called wimax_dev_init() on it before.
 466 *
 467 * @net_dev: net device the @wimax_dev is associated with. The
 468 *     function expects SET_NETDEV_DEV() and register_netdev() were
 469 *     already called on it.
 470 *
 471 * Registers the new WiMAX device, sets up the user-kernel control
 472 * interface (generic netlink) and common WiMAX infrastructure.
 473 *
 474 * Note that the parts that will allow interaction with user space are
 475 * setup at the very end, when the rest is in place, as once that
 476 * happens, the driver might get user space control requests via
 477 * netlink or from debugfs that might translate into calls into
 478 * wimax_dev->op_*().
 479 */
 480int wimax_dev_add(struct wimax_dev *wimax_dev, struct net_device *net_dev)
 481{
 482        int result;
 483        struct device *dev = net_dev->dev.parent;
 484        char addr_str[32];
 485
 486        d_fnstart(3, dev, "(wimax_dev %p net_dev %p)\n", wimax_dev, net_dev);
 487
 488        /* Do the RFKILL setup before locking, as RFKILL will call
 489         * into our functions. */
 490        wimax_dev->net_dev = net_dev;
 491        result = wimax_rfkill_add(wimax_dev);
 492        if (result < 0)
 493                goto error_rfkill_add;
 494
 495        /* Set up user-space interaction */
 496        mutex_lock(&wimax_dev->mutex);
 497        wimax_id_table_add(wimax_dev);
 498        result = wimax_debugfs_add(wimax_dev);
 499        if (result < 0) {
 500                dev_err(dev, "cannot initialize debugfs: %d\n",
 501                        result);
 502                goto error_debugfs_add;
 503        }
 504
 505        __wimax_state_set(wimax_dev, WIMAX_ST_DOWN);
 506        mutex_unlock(&wimax_dev->mutex);
 507
 508        wimax_addr_scnprint(addr_str, sizeof(addr_str),
 509                            net_dev->dev_addr, net_dev->addr_len);
 510        dev_err(dev, "WiMAX interface %s (%s) ready\n",
 511                net_dev->name, addr_str);
 512        d_fnend(3, dev, "(wimax_dev %p net_dev %p) = 0\n", wimax_dev, net_dev);
 513        return 0;
 514
 515error_debugfs_add:
 516        wimax_id_table_rm(wimax_dev);
 517        mutex_unlock(&wimax_dev->mutex);
 518        wimax_rfkill_rm(wimax_dev);
 519error_rfkill_add:
 520        d_fnend(3, dev, "(wimax_dev %p net_dev %p) = %d\n",
 521                wimax_dev, net_dev, result);
 522        return result;
 523}
 524EXPORT_SYMBOL_GPL(wimax_dev_add);
 525
 526
 527/**
 528 * wimax_dev_rm - Unregister an existing WiMAX device
 529 *
 530 * @wimax_dev: WiMAX device descriptor
 531 *
 532 * Unregisters a WiMAX device previously registered for use with
 533 * wimax_add_rm().
 534 *
 535 * IMPORTANT! Must call before calling unregister_netdev().
 536 *
 537 * After this function returns, you will not get any more user space
 538 * control requests (via netlink or debugfs) and thus to wimax_dev->ops.
 539 *
 540 * Reentrancy control is ensured by setting the state to
 541 * %__WIMAX_ST_QUIESCING. rfkill operations coming through
 542 * wimax_*rfkill*() will be stopped by the quiescing state; ops coming
 543 * from the rfkill subsystem will be stopped by the support being
 544 * removed by wimax_rfkill_rm().
 545 */
 546void wimax_dev_rm(struct wimax_dev *wimax_dev)
 547{
 548        d_fnstart(3, NULL, "(wimax_dev %p)\n", wimax_dev);
 549
 550        mutex_lock(&wimax_dev->mutex);
 551        __wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING);
 552        wimax_debugfs_rm(wimax_dev);
 553        wimax_id_table_rm(wimax_dev);
 554        __wimax_state_change(wimax_dev, WIMAX_ST_DOWN);
 555        mutex_unlock(&wimax_dev->mutex);
 556        wimax_rfkill_rm(wimax_dev);
 557        d_fnend(3, NULL, "(wimax_dev %p) = void\n", wimax_dev);
 558}
 559EXPORT_SYMBOL_GPL(wimax_dev_rm);
 560
 561
 562/* Debug framework control of debug levels */
 563struct d_level D_LEVEL[] = {
 564        D_SUBMODULE_DEFINE(debugfs),
 565        D_SUBMODULE_DEFINE(id_table),
 566        D_SUBMODULE_DEFINE(op_msg),
 567        D_SUBMODULE_DEFINE(op_reset),
 568        D_SUBMODULE_DEFINE(op_rfkill),
 569        D_SUBMODULE_DEFINE(op_state_get),
 570        D_SUBMODULE_DEFINE(stack),
 571};
 572size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL);
 573
 574
 575static const struct genl_multicast_group wimax_gnl_mcgrps[] = {
 576        { .name = "msg", },
 577};
 578
 579struct genl_family wimax_gnl_family __ro_after_init = {
 580        .name = "WiMAX",
 581        .version = WIMAX_GNL_VERSION,
 582        .hdrsize = 0,
 583        .maxattr = WIMAX_GNL_ATTR_MAX,
 584        .module = THIS_MODULE,
 585        .ops = wimax_gnl_ops,
 586        .n_ops = ARRAY_SIZE(wimax_gnl_ops),
 587        .mcgrps = wimax_gnl_mcgrps,
 588        .n_mcgrps = ARRAY_SIZE(wimax_gnl_mcgrps),
 589};
 590
 591
 592
 593/* Shutdown the wimax stack */
 594static
 595int __init wimax_subsys_init(void)
 596{
 597        int result;
 598
 599        d_fnstart(4, NULL, "()\n");
 600        d_parse_params(D_LEVEL, D_LEVEL_SIZE, wimax_debug_params,
 601                       "wimax.debug");
 602
 603        result = genl_register_family(&wimax_gnl_family);
 604        if (unlikely(result < 0)) {
 605                pr_err("cannot register generic netlink family: %d\n", result);
 606                goto error_register_family;
 607        }
 608
 609        d_fnend(4, NULL, "() = 0\n");
 610        return 0;
 611
 612error_register_family:
 613        d_fnend(4, NULL, "() = %d\n", result);
 614        return result;
 615
 616}
 617module_init(wimax_subsys_init);
 618
 619
 620/* Shutdown the wimax stack */
 621static
 622void __exit wimax_subsys_exit(void)
 623{
 624        wimax_id_table_release();
 625        genl_unregister_family(&wimax_gnl_family);
 626}
 627module_exit(wimax_subsys_exit);
 628
 629MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>");
 630MODULE_DESCRIPTION("Linux WiMAX stack");
 631MODULE_LICENSE("GPL");
 632
 633