stack.c 18 KB

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