Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
stack.c
Go to the documentation of this file.
1 /*
2  * Linux WiMAX
3  * Initialization, addition and removal of wimax devices
4  *
5  *
6  * Copyright (C) 2005-2006 Intel Corporation <[email protected]>
7  * Inaky Perez-Gonzalez <[email protected]>
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 
65 static char wimax_debug_params[128];
66 module_param_string(debug, wimax_debug_params, sizeof(wimax_debug_params),
67  0644);
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 /*
80 static 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  */
100 static
101 struct 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,
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 
147 error_put:
148  nlmsg_free(report_skb);
149 error_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  */
166 static
167 int 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);
181 out:
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 
188 static
189 void __check_new_state(enum wimax_st old_state, enum wimax_st new_state,
190  unsigned int 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  */
203 void __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,
234  | 1 << WIMAX_ST_RADIO_OFF);
235  break;
237  __check_new_state(old_state, new_state, 1 << WIMAX_ST_DOWN);
238  break;
240  __check_new_state(old_state, new_state,
242  | 1 << WIMAX_ST_RADIO_OFF);
243  break;
244  case WIMAX_ST_RADIO_OFF:
245  __check_new_state(old_state, new_state,
247  | 1 << WIMAX_ST_READY);
248  break;
249  case WIMAX_ST_READY:
250  __check_new_state(old_state, new_state,
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,
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,
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,
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;
299  break;
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);
321 out:
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 
347 void 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 }
367 
368 
376 enum 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 }
385 
386 
396 void 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 }
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  */
409 extern struct genl_ops
414 
415 static
416 struct genl_ops *wimax_gnl_ops[] = {
421 };
422 
423 
424 static
425 size_t wimax_addr_scnprint(char *addr_str, size_t addr_str_size,
426  unsigned char *addr, size_t addr_len)
427 {
428  unsigned int cnt, total;
429 
430  for (total = cnt = 0; cnt < addr_len; cnt++)
431  total += scnprintf(addr_str + total, addr_str_size - total,
432  "%02x%c", addr[cnt],
433  cnt == addr_len - 1 ? '\0' : ':');
434  return total;
435 }
436 
437 
457 int wimax_dev_add(struct wimax_dev *wimax_dev, struct net_device *net_dev)
458 {
459  int result;
460  struct device *dev = net_dev->dev.parent;
461  char addr_str[32];
462 
463  d_fnstart(3, dev, "(wimax_dev %p net_dev %p)\n", wimax_dev, net_dev);
464 
465  /* Do the RFKILL setup before locking, as RFKILL will call
466  * into our functions. */
467  wimax_dev->net_dev = net_dev;
468  result = wimax_rfkill_add(wimax_dev);
469  if (result < 0)
470  goto error_rfkill_add;
471 
472  /* Set up user-space interaction */
473  mutex_lock(&wimax_dev->mutex);
474  wimax_id_table_add(wimax_dev);
475  result = wimax_debugfs_add(wimax_dev);
476  if (result < 0) {
477  dev_err(dev, "cannot initialize debugfs: %d\n",
478  result);
479  goto error_debugfs_add;
480  }
481 
482  __wimax_state_set(wimax_dev, WIMAX_ST_DOWN);
483  mutex_unlock(&wimax_dev->mutex);
484 
485  wimax_addr_scnprint(addr_str, sizeof(addr_str),
486  net_dev->dev_addr, net_dev->addr_len);
487  dev_err(dev, "WiMAX interface %s (%s) ready\n",
488  net_dev->name, addr_str);
489  d_fnend(3, dev, "(wimax_dev %p net_dev %p) = 0\n", wimax_dev, net_dev);
490  return 0;
491 
492 error_debugfs_add:
493  wimax_id_table_rm(wimax_dev);
494  mutex_unlock(&wimax_dev->mutex);
495  wimax_rfkill_rm(wimax_dev);
496 error_rfkill_add:
497  d_fnend(3, dev, "(wimax_dev %p net_dev %p) = %d\n",
498  wimax_dev, net_dev, result);
499  return result;
500 }
502 
503 
523 void wimax_dev_rm(struct wimax_dev *wimax_dev)
524 {
525  d_fnstart(3, NULL, "(wimax_dev %p)\n", wimax_dev);
526 
527  mutex_lock(&wimax_dev->mutex);
529  wimax_debugfs_rm(wimax_dev);
530  wimax_id_table_rm(wimax_dev);
532  mutex_unlock(&wimax_dev->mutex);
533  wimax_rfkill_rm(wimax_dev);
534  d_fnend(3, NULL, "(wimax_dev %p) = void\n", wimax_dev);
535 }
537 
538 
539 /* Debug framework control of debug levels */
540 struct d_level D_LEVEL[] = {
541  D_SUBMODULE_DEFINE(debugfs),
542  D_SUBMODULE_DEFINE(id_table),
543  D_SUBMODULE_DEFINE(op_msg),
544  D_SUBMODULE_DEFINE(op_reset),
545  D_SUBMODULE_DEFINE(op_rfkill),
546  D_SUBMODULE_DEFINE(op_state_get),
548 };
549 size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL);
550 
551 
553  .id = GENL_ID_GENERATE,
554  .name = "WiMAX",
555  .version = WIMAX_GNL_VERSION,
556  .hdrsize = 0,
557  .maxattr = WIMAX_GNL_ATTR_MAX,
558 };
559 
561  .name = "msg",
562 };
563 
564 
565 
566 /* Shutdown the wimax stack */
567 static
568 int __init wimax_subsys_init(void)
569 {
570  int result, cnt;
571 
572  d_fnstart(4, NULL, "()\n");
573  d_parse_params(D_LEVEL, D_LEVEL_SIZE, wimax_debug_params,
574  "wimax.debug");
575 
576  snprintf(wimax_gnl_family.name, sizeof(wimax_gnl_family.name),
577  "WiMAX");
578  result = genl_register_family(&wimax_gnl_family);
579  if (unlikely(result < 0)) {
580  printk(KERN_ERR "cannot register generic netlink family: %d\n",
581  result);
582  goto error_register_family;
583  }
584 
585  for (cnt = 0; cnt < ARRAY_SIZE(wimax_gnl_ops); cnt++) {
586  result = genl_register_ops(&wimax_gnl_family,
587  wimax_gnl_ops[cnt]);
588  d_printf(4, NULL, "registering generic netlink op code "
589  "%u: %d\n", wimax_gnl_ops[cnt]->cmd, result);
590  if (unlikely(result < 0)) {
591  printk(KERN_ERR "cannot register generic netlink op "
592  "code %u: %d\n",
593  wimax_gnl_ops[cnt]->cmd, result);
594  goto error_register_ops;
595  }
596  }
597 
598  result = genl_register_mc_group(&wimax_gnl_family, &wimax_gnl_mcg);
599  if (result < 0)
600  goto error_mc_group;
601  d_fnend(4, NULL, "() = 0\n");
602  return 0;
603 
604 error_mc_group:
605 error_register_ops:
606  for (cnt--; cnt >= 0; cnt--)
607  genl_unregister_ops(&wimax_gnl_family,
608  wimax_gnl_ops[cnt]);
609  genl_unregister_family(&wimax_gnl_family);
610 error_register_family:
611  d_fnend(4, NULL, "() = %d\n", result);
612  return result;
613 
614 }
615 module_init(wimax_subsys_init);
616 
617 
618 /* Shutdown the wimax stack */
619 static
620 void __exit wimax_subsys_exit(void)
621 {
622  int cnt;
624  genl_unregister_mc_group(&wimax_gnl_family, &wimax_gnl_mcg);
625  for (cnt = ARRAY_SIZE(wimax_gnl_ops) - 1; cnt >= 0; cnt--)
626  genl_unregister_ops(&wimax_gnl_family,
627  wimax_gnl_ops[cnt]);
628  genl_unregister_family(&wimax_gnl_family);
629 }
630 module_exit(wimax_subsys_exit);
631 
632 MODULE_AUTHOR("Intel Corporation <[email protected]>");
633 MODULE_DESCRIPTION("Linux WiMAX stack");
634 MODULE_LICENSE("GPL");
635