stack.c 18 KB

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