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        data = genlmsg_put(report_skb, 0, wimax_gnl_mcg.id, &wimax_gnl_family,
 120                           0, WIMAX_GNL_RE_STATE_CHANGE);
 121        if (data == NULL) {
 122                dev_err(dev, "RE_STCH: can't put data into message\n");
 123                goto error_put;
 124        }
 125        *header = data;
 126
 127        result = nla_put_u8(report_skb, WIMAX_GNL_STCH_STATE_OLD, old_state);
 128        if (result < 0) {
 129                dev_err(dev, "RE_STCH: Error adding OLD attr: %d\n", result);
 130                goto error_put;
 131        }
 132        result = nla_put_u8(report_skb, WIMAX_GNL_STCH_STATE_NEW, new_state);
 133        if (result < 0) {
 134                dev_err(dev, "RE_STCH: Error adding NEW attr: %d\n", result);
 135                goto error_put;
 136        }
 137        result = nla_put_u32(report_skb, WIMAX_GNL_STCH_IFIDX,
 138                             wimax_dev->net_dev->ifindex);
 139        if (result < 0) {
 140                dev_err(dev, "RE_STCH: Error adding IFINDEX attribute\n");
 141                goto error_put;
 142        }
 143        d_fnend(3, dev, "(wimax_dev %p new_state %u old_state %u) = %p\n",
 144                wimax_dev, new_state, old_state, report_skb);
 145        return report_skb;
 146
 147error_put:
 148        nlmsg_free(report_skb);
 149error_new:
 150        d_fnend(3, dev, "(wimax_dev %p new_state %u old_state %u) = %d\n",
 151                wimax_dev, new_state, old_state, result);
 152        return ERR_PTR(result);
 153}
 154
 155
 156/*
 157 * Send a Report State Change message (as created with _alloc).
 158 *
 159 * @report_skb: as returned by wimax_gnl_re_state_change_alloc()
 160 * @header: as returned by wimax_gnl_re_state_change_alloc()
 161 *
 162 * Returns: 0 if ok, < 0 errno code on error.
 163 *
 164 * If the message is  NULL, pretend it didn't happen.
 165 */
 166static
 167int wimax_gnl_re_state_change_send(
 168        struct wimax_dev *wimax_dev, struct sk_buff *report_skb,
 169        void *header)
 170{
 171        int result = 0;
 172        struct device *dev = wimax_dev_to_dev(wimax_dev);
 173        d_fnstart(3, dev, "(wimax_dev %p report_skb %p)\n",
 174                  wimax_dev, report_skb);
 175        if (report_skb == NULL) {
 176                result = -ENOMEM;
 177                goto out;
 178        }
 179        genlmsg_end(report_skb, header);
 180        genlmsg_multicast(report_skb, 0, wimax_gnl_mcg.id, GFP_KERNEL);
 181out:
 182        d_fnend(3, dev, "(wimax_dev %p report_skb %p) = %d\n",
 183                wimax_dev, report_skb, result);
 184        return result;
 185}
 186
 187
 188static
 189void __check_new_state(enum wimax_st old_state, enum wimax_st new_state,
 190                       unsigned allowed_states_bm)
 191{
 192        if (WARN_ON(((1 << new_state) & allowed_states_bm) == 0)) {
 193                printk(KERN_ERR "SW BUG! Forbidden state change %u -> %u\n",
 194                        old_state, new_state);
 195        }
 196}
 197
 198
 199/*
 200 * Set the current state of a WiMAX device [unlocking version of
 201 * wimax_state_change().
 202 */
 203void __wimax_state_change(struct wimax_dev *wimax_dev, enum wimax_st new_state)
 204{
 205        struct device *dev = wimax_dev_to_dev(wimax_dev);
 206        enum wimax_st old_state = wimax_dev->state;
 207        struct sk_buff *stch_skb;
 208        void *header;
 209
 210        d_fnstart(3, dev, "(wimax_dev %p new_state %u [old %u])\n",
 211                  wimax_dev, new_state, old_state);
 212
 213        if (WARN_ON(new_state >= __WIMAX_ST_INVALID)) {
 214                dev_err(dev, "SW BUG: requesting invalid state %u\n",
 215                        new_state);
 216                goto out;
 217        }
 218        if (old_state == new_state)
 219                goto out;
 220        header = NULL;  /* gcc complains? can't grok why */
 221        stch_skb = wimax_gnl_re_state_change_alloc(
 222                wimax_dev, new_state, old_state, &header);
 223
 224        /* Verify the state transition and do exit-from-state actions */
 225        switch (old_state) {
 226        case __WIMAX_ST_NULL:
 227                __check_new_state(old_state, new_state,
 228                                  1 << WIMAX_ST_DOWN);
 229                break;
 230        case WIMAX_ST_DOWN:
 231                __check_new_state(old_state, new_state,
 232                                  1 << __WIMAX_ST_QUIESCING
 233                                  | 1 << WIMAX_ST_UNINITIALIZED
 234                                  | 1 << WIMAX_ST_RADIO_OFF);
 235                break;
 236        case __WIMAX_ST_QUIESCING:
 237                __check_new_state(old_state, new_state, 1 << WIMAX_ST_DOWN);
 238                break;
 239        case WIMAX_ST_UNINITIALIZED:
 240                __check_new_state(old_state, new_state,
 241                                  1 << __WIMAX_ST_QUIESCING
 242                                  | 1 << WIMAX_ST_RADIO_OFF);
 243                break;
 244        case WIMAX_ST_RADIO_OFF:
 245                __check_new_state(old_state, new_state,
 246                                  1 << __WIMAX_ST_QUIESCING
 247                                  | 1 << WIMAX_ST_READY);
 248                break;
 249        case WIMAX_ST_READY:
 250                __check_new_state(old_state, new_state,
 251                                  1 << __WIMAX_ST_QUIESCING
 252                                  | 1 << WIMAX_ST_RADIO_OFF
 253                                  | 1 << WIMAX_ST_SCANNING
 254                                  | 1 << WIMAX_ST_CONNECTING
 255                                  | 1 << WIMAX_ST_CONNECTED);
 256                break;
 257        case WIMAX_ST_SCANNING:
 258                __check_new_state(old_state, new_state,
 259                                  1 << __WIMAX_ST_QUIESCING
 260                                  | 1 << WIMAX_ST_RADIO_OFF
 261                                  | 1 << WIMAX_ST_READY
 262                                  | 1 << WIMAX_ST_CONNECTING
 263                                  | 1 << WIMAX_ST_CONNECTED);
 264                break;
 265        case WIMAX_ST_CONNECTING:
 266                __check_new_state(old_state, new_state,
 267                                  1 << __WIMAX_ST_QUIESCING
 268                                  | 1 << WIMAX_ST_RADIO_OFF
 269                                  | 1 << WIMAX_ST_READY
 270                                  | 1 << WIMAX_ST_SCANNING
 271                                  | 1 << WIMAX_ST_CONNECTED);
 272                break;
 273        case WIMAX_ST_CONNECTED:
 274                __check_new_state(old_state, new_state,
 275                                  1 << __WIMAX_ST_QUIESCING
 276                                  | 1 << WIMAX_ST_RADIO_OFF
 277                                  | 1 << WIMAX_ST_READY);
 278                netif_tx_disable(wimax_dev->net_dev);
 279                netif_carrier_off(wimax_dev->net_dev);
 280                break;
 281        case __WIMAX_ST_INVALID:
 282        default:
 283                dev_err(dev, "SW BUG: wimax_dev %p is in unknown state %u\n",
 284                        wimax_dev, wimax_dev->state);
 285                WARN_ON(1);
 286                goto out;
 287        }
 288
 289        /* Execute the actions of entry to the new state */
 290        switch (new_state) {
 291        case __WIMAX_ST_NULL:
 292                dev_err(dev, "SW BUG: wimax_dev %p entering NULL state "
 293                        "from %u\n", wimax_dev, wimax_dev->state);
 294                WARN_ON(1);             /* Nobody can enter this state */
 295                break;
 296        case WIMAX_ST_DOWN:
 297                break;
 298        case __WIMAX_ST_QUIESCING:
 299                break;
 300        case WIMAX_ST_UNINITIALIZED:
 301                break;
 302        case WIMAX_ST_RADIO_OFF:
 303                break;
 304        case WIMAX_ST_READY:
 305                break;
 306        case WIMAX_ST_SCANNING:
 307                break;
 308        case WIMAX_ST_CONNECTING:
 309                break;
 310        case WIMAX_ST_CONNECTED:
 311                netif_carrier_on(wimax_dev->net_dev);
 312                netif_wake_queue(wimax_dev->net_dev);
 313                break;
 314        case __WIMAX_ST_INVALID:
 315        default:
 316                BUG();
 317        }
 318        __wimax_state_set(wimax_dev, new_state);
 319        if (!IS_ERR(stch_skb))
 320                wimax_gnl_re_state_change_send(wimax_dev, stch_skb, header);
 321out:
 322        d_fnend(3, dev, "(wimax_dev %p new_state %u [old %u]) = void\n",
 323                wimax_dev, new_state, old_state);
 324}
 325
 326
 327/**
 328 * wimax_state_change - Set the current state of a WiMAX device
 329 *
 330 * @wimax_dev: WiMAX device descriptor (properly referenced)
 331 * @new_state: New state to switch to
 332 *
 333 * This implements the state changes for the wimax devices. It will
 334 *
 335 * - verify that the state transition is legal (for now it'll just
 336 *   print a warning if not) according to the table in
 337 *   linux/wimax.h's documentation for 'enum wimax_st'.
 338 *
 339 * - perform the actions needed for leaving the current state and
 340 *   whichever are needed for entering the new state.
 341 *
 342 * - issue a report to user space indicating the new state (and an
 343 *   optional payload with information about the new state).
 344 *
 345 * NOTE: @wimax_dev must be locked
 346 */
 347void wimax_state_change(struct wimax_dev *wimax_dev, enum wimax_st new_state)
 348{
 349        /*
 350         * A driver cannot take the wimax_dev out of the
 351         * __WIMAX_ST_NULL state unless by calling wimax_dev_add(). If
 352         * the wimax_dev's state is still NULL, we ignore any request
 353         * to change its state because it means it hasn't been yet
 354         * registered.
 355         *
 356         * There is no need to complain about it, as routines that
 357         * call this might be shared from different code paths that
 358         * are called before or after wimax_dev_add() has done its
 359         * job.
 360         */
 361        mutex_lock(&wimax_dev->mutex);
 362        if (wimax_dev->state > __WIMAX_ST_NULL)
 363                __wimax_state_change(wimax_dev, new_state);
 364        mutex_unlock(&wimax_dev->mutex);
 365}
 366EXPORT_SYMBOL_GPL(wimax_state_change);
 367
 368
 369/**
 370 * wimax_state_get() - Return the current state of a WiMAX device
 371 *
 372 * @wimax_dev: WiMAX device descriptor
 373 *
 374 * Returns: Current state of the device according to its driver.
 375 */
 376enum wimax_st wimax_state_get(struct wimax_dev *wimax_dev)
 377{
 378        enum wimax_st state;
 379        mutex_lock(&wimax_dev->mutex);
 380        state = wimax_dev->state;
 381        mutex_unlock(&wimax_dev->mutex);
 382        return state;
 383}
 384EXPORT_SYMBOL_GPL(wimax_state_get);
 385
 386
 387/**
 388 * wimax_dev_init - initialize a newly allocated instance
 389 *
 390 * @wimax_dev: WiMAX device descriptor to initialize.
 391 *
 392 * Initializes fields of a freshly allocated @wimax_dev instance. This
 393 * function assumes that after allocation, the memory occupied by
 394 * @wimax_dev was zeroed.
 395 */
 396void wimax_dev_init(struct wimax_dev *wimax_dev)
 397{
 398        INIT_LIST_HEAD(&wimax_dev->id_table_node);
 399        __wimax_state_set(wimax_dev, __WIMAX_ST_NULL);
 400        mutex_init(&wimax_dev->mutex);
 401        mutex_init(&wimax_dev->mutex_reset);
 402}
 403EXPORT_SYMBOL_GPL(wimax_dev_init);
 404
 405/*
 406 * This extern is declared here because it's easier to keep track --
 407 * both declarations are a list of the same
 408 */
 409extern struct genl_ops
 410        wimax_gnl_msg_from_user,
 411        wimax_gnl_reset,
 412        wimax_gnl_rfkill,
 413        wimax_gnl_state_get;
 414
 415static
 416struct genl_ops *wimax_gnl_ops[] = {
 417        &wimax_gnl_msg_from_user,
 418        &wimax_gnl_reset,
 419        &wimax_gnl_rfkill,
 420        &wimax_gnl_state_get,
 421};
 422
 423
 424static
 425size_t wimax_addr_scnprint(char *addr_str, size_t addr_str_size,
 426                           unsigned char *addr, size_t addr_len)
 427{
 428        unsigned cnt, total;
 429        for (total = cnt = 0; cnt < addr_len; cnt++)
 430                total += scnprintf(addr_str + total, addr_str_size - total,
 431                                   "%02x%c", addr[cnt],
 432                                   cnt == addr_len - 1 ? '\0' : ':');
 433        return total;
 434}
 435
 436
 437/**
 438 * wimax_dev_add - Register a new WiMAX device
 439 *
 440 * @wimax_dev: WiMAX device descriptor (as embedded in your @net_dev's
 441 *     priv data). You must have called wimax_dev_init() on it before.
 442 *
 443 * @net_dev: net device the @wimax_dev is associated with. The
 444 *     function expects SET_NETDEV_DEV() and register_netdev() were
 445 *     already called on it.
 446 *
 447 * Registers the new WiMAX device, sets up the user-kernel control
 448 * interface (generic netlink) and common WiMAX infrastructure.
 449 *
 450 * Note that the parts that will allow interaction with user space are
 451 * setup at the very end, when the rest is in place, as once that
 452 * happens, the driver might get user space control requests via
 453 * netlink or from debugfs that might translate into calls into
 454 * wimax_dev->op_*().
 455 */
 456int wimax_dev_add(struct wimax_dev *wimax_dev, struct net_device *net_dev)
 457{
 458        int result;
 459        struct device *dev = net_dev->dev.parent;
 460        char addr_str[32];
 461
 462        d_fnstart(3, dev, "(wimax_dev %p net_dev %p)\n", wimax_dev, net_dev);
 463
 464        /* Do the RFKILL setup before locking, as RFKILL will call
 465         * into our functions. */
 466        wimax_dev->net_dev = net_dev;
 467        result = wimax_rfkill_add(wimax_dev);
 468        if (result < 0)
 469                goto error_rfkill_add;
 470
 471        /* Set up user-space interaction */
 472        mutex_lock(&wimax_dev->mutex);
 473        wimax_id_table_add(wimax_dev);
 474        result = wimax_debugfs_add(wimax_dev);
 475        if (result < 0) {
 476                dev_err(dev, "cannot initialize debugfs: %d\n",
 477                        result);
 478                goto error_debugfs_add;
 479        }
 480
 481        __wimax_state_set(wimax_dev, WIMAX_ST_DOWN);
 482        mutex_unlock(&wimax_dev->mutex);
 483
 484        wimax_addr_scnprint(addr_str, sizeof(addr_str),
 485                            net_dev->dev_addr, net_dev->addr_len);
 486        dev_err(dev, "WiMAX interface %s (%s) ready\n",
 487                net_dev->name, addr_str);
 488        d_fnend(3, dev, "(wimax_dev %p net_dev %p) = 0\n", wimax_dev, net_dev);
 489        return 0;
 490
 491error_debugfs_add:
 492        wimax_id_table_rm(wimax_dev);
 493        mutex_unlock(&wimax_dev->mutex);
 494        wimax_rfkill_rm(wimax_dev);
 495error_rfkill_add:
 496        d_fnend(3, dev, "(wimax_dev %p net_dev %p) = %d\n",
 497                wimax_dev, net_dev, result);
 498        return result;
 499}
 500EXPORT_SYMBOL_GPL(wimax_dev_add);
 501
 502
 503/**
 504 * wimax_dev_rm - Unregister an existing WiMAX device
 505 *
 506 * @wimax_dev: WiMAX device descriptor
 507 *
 508 * Unregisters a WiMAX device previously registered for use with
 509 * wimax_add_rm().
 510 *
 511 * IMPORTANT! Must call before calling unregister_netdev().
 512 *
 513 * After this function returns, you will not get any more user space
 514 * control requests (via netlink or debugfs) and thus to wimax_dev->ops.
 515 *
 516 * Reentrancy control is ensured by setting the state to
 517 * %__WIMAX_ST_QUIESCING. rfkill operations coming through
 518 * wimax_*rfkill*() will be stopped by the quiescing state; ops coming
 519 * from the rfkill subsystem will be stopped by the support being
 520 * removed by wimax_rfkill_rm().
 521 */
 522void wimax_dev_rm(struct wimax_dev *wimax_dev)
 523{
 524        d_fnstart(3, NULL, "(wimax_dev %p)\n", wimax_dev);
 525
 526        mutex_lock(&wimax_dev->mutex);
 527        __wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING);
 528        wimax_debugfs_rm(wimax_dev);
 529        wimax_id_table_rm(wimax_dev);
 530        __wimax_state_change(wimax_dev, WIMAX_ST_DOWN);
 531        mutex_unlock(&wimax_dev->mutex);
 532        wimax_rfkill_rm(wimax_dev);
 533        d_fnend(3, NULL, "(wimax_dev %p) = void\n", wimax_dev);
 534}
 535EXPORT_SYMBOL_GPL(wimax_dev_rm);
 536
 537
 538/* Debug framework control of debug levels */
 539struct d_level D_LEVEL[] = {
 540        D_SUBMODULE_DEFINE(debugfs),
 541        D_SUBMODULE_DEFINE(id_table),
 542        D_SUBMODULE_DEFINE(op_msg),
 543        D_SUBMODULE_DEFINE(op_reset),
 544        D_SUBMODULE_DEFINE(op_rfkill),
 545        D_SUBMODULE_DEFINE(op_state_get),
 546        D_SUBMODULE_DEFINE(stack),
 547};
 548size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL);
 549
 550
 551struct genl_family wimax_gnl_family = {
 552        .id = GENL_ID_GENERATE,
 553        .name = "WiMAX",
 554        .version = WIMAX_GNL_VERSION,
 555        .hdrsize = 0,
 556        .maxattr = WIMAX_GNL_ATTR_MAX,
 557};
 558
 559struct genl_multicast_group wimax_gnl_mcg = {
 560        .name = "msg",
 561};
 562
 563
 564
 565/* Shutdown the wimax stack */
 566static
 567int __init wimax_subsys_init(void)
 568{
 569        int result, cnt;
 570
 571        d_fnstart(4, NULL, "()\n");
 572        d_parse_params(D_LEVEL, D_LEVEL_SIZE, wimax_debug_params,
 573                       "wimax.debug");
 574
 575        snprintf(wimax_gnl_family.name, sizeof(wimax_gnl_family.name),
 576                 "WiMAX");
 577        result = genl_register_family(&wimax_gnl_family);
 578        if (unlikely(result < 0)) {
 579                printk(KERN_ERR "cannot register generic netlink family: %d\n",
 580                       result);
 581                goto error_register_family;
 582        }
 583
 584        for (cnt = 0; cnt < ARRAY_SIZE(wimax_gnl_ops); cnt++) {
 585                result = genl_register_ops(&wimax_gnl_family,
 586                                           wimax_gnl_ops[cnt]);
 587                d_printf(4, NULL, "registering generic netlink op code "
 588                         "%u: %d\n", wimax_gnl_ops[cnt]->cmd, result);
 589                if (unlikely(result < 0)) {
 590                        printk(KERN_ERR "cannot register generic netlink op "
 591                               "code %u: %d\n",
 592                               wimax_gnl_ops[cnt]->cmd, result);
 593                        goto error_register_ops;
 594                }
 595        }
 596
 597        result = genl_register_mc_group(&wimax_gnl_family, &wimax_gnl_mcg);
 598        if (result < 0)
 599                goto error_mc_group;
 600        d_fnend(4, NULL, "() = 0\n");
 601        return 0;
 602
 603error_mc_group:
 604error_register_ops:
 605        for (cnt--; cnt >= 0; cnt--)
 606                genl_unregister_ops(&wimax_gnl_family,
 607                                    wimax_gnl_ops[cnt]);
 608        genl_unregister_family(&wimax_gnl_family);
 609error_register_family:
 610        d_fnend(4, NULL, "() = %d\n", result);
 611        return result;
 612
 613}
 614module_init(wimax_subsys_init);
 615
 616
 617/* Shutdown the wimax stack */
 618static
 619void __exit wimax_subsys_exit(void)
 620{
 621        int cnt;
 622        wimax_id_table_release();
 623        genl_unregister_mc_group(&wimax_gnl_family, &wimax_gnl_mcg);
 624        for (cnt = ARRAY_SIZE(wimax_gnl_ops) - 1; cnt >= 0; cnt--)
 625                genl_unregister_ops(&wimax_gnl_family,
 626                                    wimax_gnl_ops[cnt]);
 627        genl_unregister_family(&wimax_gnl_family);
 628}
 629module_exit(wimax_subsys_exit);
 630
 631MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>");
 632MODULE_DESCRIPTION("Linux WiMAX stack");
 633MODULE_LICENSE("GPL");
 634
 635