stack.c 17 KB

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