stack.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  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 (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. return;
  305. }
  306. /**
  307. * wimax_state_change - Set the current state of a WiMAX device
  308. *
  309. * @wimax_dev: WiMAX device descriptor (properly referenced)
  310. * @new_state: New state to switch to
  311. *
  312. * This implements the state changes for the wimax devices. It will
  313. *
  314. * - verify that the state transition is legal (for now it'll just
  315. * print a warning if not) according to the table in
  316. * linux/wimax.h's documentation for 'enum wimax_st'.
  317. *
  318. * - perform the actions needed for leaving the current state and
  319. * whichever are needed for entering the new state.
  320. *
  321. * - issue a report to user space indicating the new state (and an
  322. * optional payload with information about the new state).
  323. *
  324. * NOTE: @wimax_dev must be locked
  325. */
  326. void wimax_state_change(struct wimax_dev *wimax_dev, enum wimax_st new_state)
  327. {
  328. /*
  329. * A driver cannot take the wimax_dev out of the
  330. * __WIMAX_ST_NULL state unless by calling wimax_dev_add(). If
  331. * the wimax_dev's state is still NULL, we ignore any request
  332. * to change its state because it means it hasn't been yet
  333. * registered.
  334. *
  335. * There is no need to complain about it, as routines that
  336. * call this might be shared from different code paths that
  337. * are called before or after wimax_dev_add() has done its
  338. * job.
  339. */
  340. mutex_lock(&wimax_dev->mutex);
  341. if (wimax_dev->state > __WIMAX_ST_NULL)
  342. __wimax_state_change(wimax_dev, new_state);
  343. mutex_unlock(&wimax_dev->mutex);
  344. return;
  345. }
  346. EXPORT_SYMBOL_GPL(wimax_state_change);
  347. /**
  348. * wimax_state_get() - Return the current state of a WiMAX device
  349. *
  350. * @wimax_dev: WiMAX device descriptor
  351. *
  352. * Returns: Current state of the device according to its driver.
  353. */
  354. enum wimax_st wimax_state_get(struct wimax_dev *wimax_dev)
  355. {
  356. enum wimax_st state;
  357. mutex_lock(&wimax_dev->mutex);
  358. state = wimax_dev->state;
  359. mutex_unlock(&wimax_dev->mutex);
  360. return state;
  361. }
  362. EXPORT_SYMBOL_GPL(wimax_state_get);
  363. /**
  364. * wimax_dev_init - initialize a newly allocated instance
  365. *
  366. * @wimax_dev: WiMAX device descriptor to initialize.
  367. *
  368. * Initializes fields of a freshly allocated @wimax_dev instance. This
  369. * function assumes that after allocation, the memory occupied by
  370. * @wimax_dev was zeroed.
  371. */
  372. void wimax_dev_init(struct wimax_dev *wimax_dev)
  373. {
  374. INIT_LIST_HEAD(&wimax_dev->id_table_node);
  375. __wimax_state_set(wimax_dev, __WIMAX_ST_NULL);
  376. mutex_init(&wimax_dev->mutex);
  377. mutex_init(&wimax_dev->mutex_reset);
  378. }
  379. EXPORT_SYMBOL_GPL(wimax_dev_init);
  380. /*
  381. * This extern is declared here because it's easier to keep track --
  382. * both declarations are a list of the same
  383. */
  384. extern struct genl_ops
  385. wimax_gnl_msg_from_user,
  386. wimax_gnl_reset,
  387. wimax_gnl_rfkill,
  388. wimax_gnl_state_get;
  389. static
  390. struct genl_ops *wimax_gnl_ops[] = {
  391. &wimax_gnl_msg_from_user,
  392. &wimax_gnl_reset,
  393. &wimax_gnl_rfkill,
  394. &wimax_gnl_state_get,
  395. };
  396. static
  397. size_t wimax_addr_scnprint(char *addr_str, size_t addr_str_size,
  398. unsigned char *addr, size_t addr_len)
  399. {
  400. unsigned cnt, total;
  401. for (total = cnt = 0; cnt < addr_len; cnt++)
  402. total += scnprintf(addr_str + total, addr_str_size - total,
  403. "%02x%c", addr[cnt],
  404. cnt == addr_len - 1 ? '\0' : ':');
  405. return total;
  406. }
  407. /**
  408. * wimax_dev_add - Register a new WiMAX device
  409. *
  410. * @wimax_dev: WiMAX device descriptor (as embedded in your @net_dev's
  411. * priv data). You must have called wimax_dev_init() on it before.
  412. *
  413. * @net_dev: net device the @wimax_dev is associated with. The
  414. * function expects SET_NETDEV_DEV() and register_netdev() were
  415. * already called on it.
  416. *
  417. * Registers the new WiMAX device, sets up the user-kernel control
  418. * interface (generic netlink) and common WiMAX infrastructure.
  419. *
  420. * Note that the parts that will allow interaction with user space are
  421. * setup at the very end, when the rest is in place, as once that
  422. * happens, the driver might get user space control requests via
  423. * netlink or from debugfs that might translate into calls into
  424. * wimax_dev->op_*().
  425. */
  426. int wimax_dev_add(struct wimax_dev *wimax_dev, struct net_device *net_dev)
  427. {
  428. int result;
  429. struct device *dev = net_dev->dev.parent;
  430. char addr_str[32];
  431. d_fnstart(3, dev, "(wimax_dev %p net_dev %p)\n", wimax_dev, net_dev);
  432. /* Do the RFKILL setup before locking, as RFKILL will call
  433. * into our functions. */
  434. wimax_dev->net_dev = net_dev;
  435. result = wimax_rfkill_add(wimax_dev);
  436. if (result < 0)
  437. goto error_rfkill_add;
  438. /* Set up user-space interaction */
  439. mutex_lock(&wimax_dev->mutex);
  440. wimax_id_table_add(wimax_dev);
  441. result = wimax_debugfs_add(wimax_dev);
  442. if (result < 0) {
  443. dev_err(dev, "cannot initialize debugfs: %d\n",
  444. result);
  445. goto error_debugfs_add;
  446. }
  447. __wimax_state_set(wimax_dev, WIMAX_ST_DOWN);
  448. mutex_unlock(&wimax_dev->mutex);
  449. wimax_addr_scnprint(addr_str, sizeof(addr_str),
  450. net_dev->dev_addr, net_dev->addr_len);
  451. dev_err(dev, "WiMAX interface %s (%s) ready\n",
  452. net_dev->name, addr_str);
  453. d_fnend(3, dev, "(wimax_dev %p net_dev %p) = 0\n", wimax_dev, net_dev);
  454. return 0;
  455. error_debugfs_add:
  456. wimax_id_table_rm(wimax_dev);
  457. mutex_unlock(&wimax_dev->mutex);
  458. wimax_rfkill_rm(wimax_dev);
  459. error_rfkill_add:
  460. d_fnend(3, dev, "(wimax_dev %p net_dev %p) = %d\n",
  461. wimax_dev, net_dev, result);
  462. return result;
  463. }
  464. EXPORT_SYMBOL_GPL(wimax_dev_add);
  465. /**
  466. * wimax_dev_rm - Unregister an existing WiMAX device
  467. *
  468. * @wimax_dev: WiMAX device descriptor
  469. *
  470. * Unregisters a WiMAX device previously registered for use with
  471. * wimax_add_rm().
  472. *
  473. * IMPORTANT! Must call before calling unregister_netdev().
  474. *
  475. * After this function returns, you will not get any more user space
  476. * control requests (via netlink or debugfs) and thus to wimax_dev->ops.
  477. *
  478. * Reentrancy control is ensured by setting the state to
  479. * %__WIMAX_ST_QUIESCING. rfkill operations coming through
  480. * wimax_*rfkill*() will be stopped by the quiescing state; ops coming
  481. * from the rfkill subsystem will be stopped by the support being
  482. * removed by wimax_rfkill_rm().
  483. */
  484. void wimax_dev_rm(struct wimax_dev *wimax_dev)
  485. {
  486. d_fnstart(3, NULL, "(wimax_dev %p)\n", wimax_dev);
  487. mutex_lock(&wimax_dev->mutex);
  488. __wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING);
  489. wimax_debugfs_rm(wimax_dev);
  490. wimax_id_table_rm(wimax_dev);
  491. __wimax_state_change(wimax_dev, WIMAX_ST_DOWN);
  492. mutex_unlock(&wimax_dev->mutex);
  493. wimax_rfkill_rm(wimax_dev);
  494. d_fnend(3, NULL, "(wimax_dev %p) = void\n", wimax_dev);
  495. }
  496. EXPORT_SYMBOL_GPL(wimax_dev_rm);
  497. /* Debug framework control of debug levels */
  498. struct d_level D_LEVEL[] = {
  499. D_SUBMODULE_DEFINE(debugfs),
  500. D_SUBMODULE_DEFINE(id_table),
  501. D_SUBMODULE_DEFINE(op_msg),
  502. D_SUBMODULE_DEFINE(op_reset),
  503. D_SUBMODULE_DEFINE(op_rfkill),
  504. D_SUBMODULE_DEFINE(op_state_get),
  505. D_SUBMODULE_DEFINE(stack),
  506. };
  507. size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL);
  508. struct genl_family wimax_gnl_family = {
  509. .id = GENL_ID_GENERATE,
  510. .name = "WiMAX",
  511. .version = WIMAX_GNL_VERSION,
  512. .hdrsize = 0,
  513. .maxattr = WIMAX_GNL_ATTR_MAX,
  514. };
  515. struct genl_multicast_group wimax_gnl_mcg = {
  516. .name = "msg",
  517. };
  518. /* Shutdown the wimax stack */
  519. static
  520. int __init wimax_subsys_init(void)
  521. {
  522. int result, cnt;
  523. d_fnstart(4, NULL, "()\n");
  524. d_parse_params(D_LEVEL, D_LEVEL_SIZE, wimax_debug_params,
  525. "wimax.debug");
  526. snprintf(wimax_gnl_family.name, sizeof(wimax_gnl_family.name),
  527. "WiMAX");
  528. result = genl_register_family(&wimax_gnl_family);
  529. if (unlikely(result < 0)) {
  530. printk(KERN_ERR "cannot register generic netlink family: %d\n",
  531. result);
  532. goto error_register_family;
  533. }
  534. for (cnt = 0; cnt < ARRAY_SIZE(wimax_gnl_ops); cnt++) {
  535. result = genl_register_ops(&wimax_gnl_family,
  536. wimax_gnl_ops[cnt]);
  537. d_printf(4, NULL, "registering generic netlink op code "
  538. "%u: %d\n", wimax_gnl_ops[cnt]->cmd, result);
  539. if (unlikely(result < 0)) {
  540. printk(KERN_ERR "cannot register generic netlink op "
  541. "code %u: %d\n",
  542. wimax_gnl_ops[cnt]->cmd, result);
  543. goto error_register_ops;
  544. }
  545. }
  546. result = genl_register_mc_group(&wimax_gnl_family, &wimax_gnl_mcg);
  547. if (result < 0)
  548. goto error_mc_group;
  549. d_fnend(4, NULL, "() = 0\n");
  550. return 0;
  551. error_mc_group:
  552. error_register_ops:
  553. for (cnt--; cnt >= 0; cnt--)
  554. genl_unregister_ops(&wimax_gnl_family,
  555. wimax_gnl_ops[cnt]);
  556. genl_unregister_family(&wimax_gnl_family);
  557. error_register_family:
  558. d_fnend(4, NULL, "() = %d\n", result);
  559. return result;
  560. }
  561. module_init(wimax_subsys_init);
  562. /* Shutdown the wimax stack */
  563. static
  564. void __exit wimax_subsys_exit(void)
  565. {
  566. int cnt;
  567. wimax_id_table_release();
  568. genl_unregister_mc_group(&wimax_gnl_family, &wimax_gnl_mcg);
  569. for (cnt = ARRAY_SIZE(wimax_gnl_ops) - 1; cnt >= 0; cnt--)
  570. genl_unregister_ops(&wimax_gnl_family,
  571. wimax_gnl_ops[cnt]);
  572. genl_unregister_family(&wimax_gnl_family);
  573. }
  574. module_exit(wimax_subsys_exit);
  575. MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>");
  576. MODULE_DESCRIPTION("Linux WiMAX stack");
  577. MODULE_LICENSE("GPL");