Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.8.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Linux WiMAX
  4 * Initialization, addition and removal of wimax devices
  5 *
  6 * Copyright (C) 2005-2006 Intel Corporation <linux-wimax@intel.com>
  7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
  8 *
  9 * This implements:
 10 *
 11 *   - basic life cycle of 'struct wimax_dev' [wimax_dev_*()]; on
 12 *     addition/registration initialize all subfields and allocate
 13 *     generic netlink resources for user space communication. On
 14 *     removal/unregistration, undo all that.
 15 *
 16 *   - device state machine [wimax_state_change()] and support to send
 17 *     reports to user space when the state changes
 18 *     [wimax_gnl_re_state_change*()].
 19 *
 20 * See include/net/wimax.h for rationales and design.
 21 *
 22 * ROADMAP
 23 *
 24 * [__]wimax_state_change()     Called by drivers to update device's state
 25 *   wimax_gnl_re_state_change_alloc()
 26 *   wimax_gnl_re_state_change_send()
 27 *
 28 * wimax_dev_init()	        Init a device
 29 * wimax_dev_add()              Register
 30 *   wimax_rfkill_add()
 31 *   wimax_gnl_add()            Register all the generic netlink resources.
 32 *   wimax_id_table_add()
 33 * wimax_dev_rm()               Unregister
 34 *   wimax_id_table_rm()
 35 *   wimax_gnl_rm()
 36 *   wimax_rfkill_rm()
 37 */
 38#include <linux/device.h>
 39#include <linux/gfp.h>
 40#include <net/genetlink.h>
 41#include <linux/netdevice.h>
 42#include <linux/wimax.h>
 43#include <linux/module.h>
 44#include "wimax-internal.h"
 45
 46
 47#define D_SUBMODULE stack
 48#include "debug-levels.h"
 49
 50static char wimax_debug_params[128];
 51module_param_string(debug, wimax_debug_params, sizeof(wimax_debug_params),
 52		    0644);
 53MODULE_PARM_DESC(debug,
 54		 "String of space-separated NAME:VALUE pairs, where NAMEs "
 55		 "are the different debug submodules and VALUE are the "
 56		 "initial debug value to set.");
 57
 58/*
 59 * Authoritative source for the RE_STATE_CHANGE attribute policy
 60 *
 61 * We don't really use it here, but /me likes to keep the definition
 62 * close to where the data is generated.
 63 */
 64/*
 65static const struct nla_policy wimax_gnl_re_status_change[WIMAX_GNL_ATTR_MAX + 1] = {
 66	[WIMAX_GNL_STCH_STATE_OLD] = { .type = NLA_U8 },
 67	[WIMAX_GNL_STCH_STATE_NEW] = { .type = NLA_U8 },
 68};
 69*/
 70
 71
 72/*
 73 * Allocate a Report State Change message
 74 *
 75 * @header: save it, you need it for _send()
 76 *
 77 * Creates and fills a basic state change message; different code
 78 * paths can then add more attributes to the message as needed.
 79 *
 80 * Use wimax_gnl_re_state_change_send() to send the returned skb.
 81 *
 82 * Returns: skb with the genl message if ok, IS_ERR() ptr on error
 83 *     with an errno code.
 84 */
 85static
 86struct sk_buff *wimax_gnl_re_state_change_alloc(
 87	struct wimax_dev *wimax_dev,
 88	enum wimax_st new_state, enum wimax_st old_state,
 89	void **header)
 90{
 91	int result;
 92	struct device *dev = wimax_dev_to_dev(wimax_dev);
 93	void *data;
 94	struct sk_buff *report_skb;
 95
 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	/* FIXME: sending a group ID as the seq is wrong */
105	data = genlmsg_put(report_skb, 0, wimax_gnl_family.mcgrp_offset,
106			   &wimax_gnl_family, 0, WIMAX_GNL_RE_STATE_CHANGE);
107	if (data == NULL) {
108		dev_err(dev, "RE_STCH: can't put data into message\n");
109		goto error_put;
110	}
111	*header = data;
112
113	result = nla_put_u8(report_skb, WIMAX_GNL_STCH_STATE_OLD, old_state);
114	if (result < 0) {
115		dev_err(dev, "RE_STCH: Error adding OLD attr: %d\n", result);
116		goto error_put;
117	}
118	result = nla_put_u8(report_skb, WIMAX_GNL_STCH_STATE_NEW, new_state);
119	if (result < 0) {
120		dev_err(dev, "RE_STCH: Error adding NEW attr: %d\n", result);
121		goto error_put;
122	}
123	result = nla_put_u32(report_skb, WIMAX_GNL_STCH_IFIDX,
124			     wimax_dev->net_dev->ifindex);
125	if (result < 0) {
126		dev_err(dev, "RE_STCH: Error adding IFINDEX attribute\n");
127		goto error_put;
128	}
129	d_fnend(3, dev, "(wimax_dev %p new_state %u old_state %u) = %p\n",
130		wimax_dev, new_state, old_state, report_skb);
131	return report_skb;
132
133error_put:
134	nlmsg_free(report_skb);
135error_new:
136	d_fnend(3, dev, "(wimax_dev %p new_state %u old_state %u) = %d\n",
137		wimax_dev, new_state, old_state, result);
138	return ERR_PTR(result);
139}
140
141
142/*
143 * Send a Report State Change message (as created with _alloc).
144 *
145 * @report_skb: as returned by wimax_gnl_re_state_change_alloc()
146 * @header: as returned by wimax_gnl_re_state_change_alloc()
147 *
148 * Returns: 0 if ok, < 0 errno code on error.
149 *
150 * If the message is  NULL, pretend it didn't happen.
151 */
152static
153int wimax_gnl_re_state_change_send(
154	struct wimax_dev *wimax_dev, struct sk_buff *report_skb,
155	void *header)
156{
157	int result = 0;
158	struct device *dev = wimax_dev_to_dev(wimax_dev);
159	d_fnstart(3, dev, "(wimax_dev %p report_skb %p)\n",
160		  wimax_dev, report_skb);
161	if (report_skb == NULL) {
162		result = -ENOMEM;
163		goto out;
164	}
165	genlmsg_end(report_skb, header);
166	genlmsg_multicast(&wimax_gnl_family, report_skb, 0, 0, GFP_KERNEL);
167out:
168	d_fnend(3, dev, "(wimax_dev %p report_skb %p) = %d\n",
169		wimax_dev, report_skb, result);
170	return result;
171}
172
173
174static
175void __check_new_state(enum wimax_st old_state, enum wimax_st new_state,
176		       unsigned int allowed_states_bm)
177{
178	if (WARN_ON(((1 << new_state) & allowed_states_bm) == 0)) {
179		pr_err("SW BUG! Forbidden state change %u -> %u\n",
180		       old_state, new_state);
181	}
182}
183
184
185/*
186 * Set the current state of a WiMAX device [unlocking version of
187 * wimax_state_change().
188 */
189void __wimax_state_change(struct wimax_dev *wimax_dev, enum wimax_st new_state)
190{
191	struct device *dev = wimax_dev_to_dev(wimax_dev);
192	enum wimax_st old_state = wimax_dev->state;
193	struct sk_buff *stch_skb;
194	void *header;
195
196	d_fnstart(3, dev, "(wimax_dev %p new_state %u [old %u])\n",
197		  wimax_dev, new_state, old_state);
198
199	if (WARN_ON(new_state >= __WIMAX_ST_INVALID)) {
200		dev_err(dev, "SW BUG: requesting invalid state %u\n",
201			new_state);
202		goto out;
203	}
204	if (old_state == new_state)
205		goto out;
206	header = NULL;	/* gcc complains? can't grok why */
207	stch_skb = wimax_gnl_re_state_change_alloc(
208		wimax_dev, new_state, old_state, &header);
209
210	/* Verify the state transition and do exit-from-state actions */
211	switch (old_state) {
212	case __WIMAX_ST_NULL:
213		__check_new_state(old_state, new_state,
214				  1 << WIMAX_ST_DOWN);
215		break;
216	case WIMAX_ST_DOWN:
217		__check_new_state(old_state, new_state,
218				  1 << __WIMAX_ST_QUIESCING
219				  | 1 << WIMAX_ST_UNINITIALIZED
220				  | 1 << WIMAX_ST_RADIO_OFF);
221		break;
222	case __WIMAX_ST_QUIESCING:
223		__check_new_state(old_state, new_state, 1 << WIMAX_ST_DOWN);
224		break;
225	case WIMAX_ST_UNINITIALIZED:
226		__check_new_state(old_state, new_state,
227				  1 << __WIMAX_ST_QUIESCING
228				  | 1 << WIMAX_ST_RADIO_OFF);
229		break;
230	case WIMAX_ST_RADIO_OFF:
231		__check_new_state(old_state, new_state,
232				  1 << __WIMAX_ST_QUIESCING
233				  | 1 << WIMAX_ST_READY);
234		break;
235	case WIMAX_ST_READY:
236		__check_new_state(old_state, new_state,
237				  1 << __WIMAX_ST_QUIESCING
238				  | 1 << WIMAX_ST_RADIO_OFF
239				  | 1 << WIMAX_ST_SCANNING
240				  | 1 << WIMAX_ST_CONNECTING
241				  | 1 << WIMAX_ST_CONNECTED);
242		break;
243	case WIMAX_ST_SCANNING:
244		__check_new_state(old_state, new_state,
245				  1 << __WIMAX_ST_QUIESCING
246				  | 1 << WIMAX_ST_RADIO_OFF
247				  | 1 << WIMAX_ST_READY
248				  | 1 << WIMAX_ST_CONNECTING
249				  | 1 << WIMAX_ST_CONNECTED);
250		break;
251	case WIMAX_ST_CONNECTING:
252		__check_new_state(old_state, new_state,
253				  1 << __WIMAX_ST_QUIESCING
254				  | 1 << WIMAX_ST_RADIO_OFF
255				  | 1 << WIMAX_ST_READY
256				  | 1 << WIMAX_ST_SCANNING
257				  | 1 << WIMAX_ST_CONNECTED);
258		break;
259	case WIMAX_ST_CONNECTED:
260		__check_new_state(old_state, new_state,
261				  1 << __WIMAX_ST_QUIESCING
262				  | 1 << WIMAX_ST_RADIO_OFF
263				  | 1 << WIMAX_ST_READY);
264		netif_tx_disable(wimax_dev->net_dev);
265		netif_carrier_off(wimax_dev->net_dev);
266		break;
267	case __WIMAX_ST_INVALID:
268	default:
269		dev_err(dev, "SW BUG: wimax_dev %p is in unknown state %u\n",
270			wimax_dev, wimax_dev->state);
271		WARN_ON(1);
272		goto out;
273	}
274
275	/* Execute the actions of entry to the new state */
276	switch (new_state) {
277	case __WIMAX_ST_NULL:
278		dev_err(dev, "SW BUG: wimax_dev %p entering NULL state "
279			"from %u\n", wimax_dev, wimax_dev->state);
280		WARN_ON(1);		/* Nobody can enter this state */
281		break;
282	case WIMAX_ST_DOWN:
283		break;
284	case __WIMAX_ST_QUIESCING:
285		break;
286	case WIMAX_ST_UNINITIALIZED:
287		break;
288	case WIMAX_ST_RADIO_OFF:
289		break;
290	case WIMAX_ST_READY:
291		break;
292	case WIMAX_ST_SCANNING:
293		break;
294	case WIMAX_ST_CONNECTING:
295		break;
296	case WIMAX_ST_CONNECTED:
297		netif_carrier_on(wimax_dev->net_dev);
298		netif_wake_queue(wimax_dev->net_dev);
299		break;
300	case __WIMAX_ST_INVALID:
301	default:
302		BUG();
303	}
304	__wimax_state_set(wimax_dev, new_state);
305	if (!IS_ERR(stch_skb))
306		wimax_gnl_re_state_change_send(wimax_dev, stch_skb, header);
307out:
308	d_fnend(3, dev, "(wimax_dev %p new_state %u [old %u]) = void\n",
309		wimax_dev, new_state, old_state);
310}
311
312
313/**
314 * wimax_state_change - Set the current state of a WiMAX device
315 *
316 * @wimax_dev: WiMAX device descriptor (properly referenced)
317 * @new_state: New state to switch to
318 *
319 * This implements the state changes for the wimax devices. It will
320 *
321 * - verify that the state transition is legal (for now it'll just
322 *   print a warning if not) according to the table in
323 *   linux/wimax.h's documentation for 'enum wimax_st'.
324 *
325 * - perform the actions needed for leaving the current state and
326 *   whichever are needed for entering the new state.
327 *
328 * - issue a report to user space indicating the new state (and an
329 *   optional payload with information about the new state).
330 *
331 * NOTE: @wimax_dev must be locked
332 */
333void wimax_state_change(struct wimax_dev *wimax_dev, enum wimax_st new_state)
334{
335	/*
336	 * A driver cannot take the wimax_dev out of the
337	 * __WIMAX_ST_NULL state unless by calling wimax_dev_add(). If
338	 * the wimax_dev's state is still NULL, we ignore any request
339	 * to change its state because it means it hasn't been yet
340	 * registered.
341	 *
342	 * There is no need to complain about it, as routines that
343	 * call this might be shared from different code paths that
344	 * are called before or after wimax_dev_add() has done its
345	 * job.
346	 */
347	mutex_lock(&wimax_dev->mutex);
348	if (wimax_dev->state > __WIMAX_ST_NULL)
349		__wimax_state_change(wimax_dev, new_state);
350	mutex_unlock(&wimax_dev->mutex);
351}
352EXPORT_SYMBOL_GPL(wimax_state_change);
353
354
355/**
356 * wimax_state_get() - Return the current state of a WiMAX device
357 *
358 * @wimax_dev: WiMAX device descriptor
359 *
360 * Returns: Current state of the device according to its driver.
361 */
362enum wimax_st wimax_state_get(struct wimax_dev *wimax_dev)
363{
364	enum wimax_st state;
365	mutex_lock(&wimax_dev->mutex);
366	state = wimax_dev->state;
367	mutex_unlock(&wimax_dev->mutex);
368	return state;
369}
370EXPORT_SYMBOL_GPL(wimax_state_get);
371
372
373/**
374 * wimax_dev_init - initialize a newly allocated instance
375 *
376 * @wimax_dev: WiMAX device descriptor to initialize.
377 *
378 * Initializes fields of a freshly allocated @wimax_dev instance. This
379 * function assumes that after allocation, the memory occupied by
380 * @wimax_dev was zeroed.
381 */
382void wimax_dev_init(struct wimax_dev *wimax_dev)
383{
384	INIT_LIST_HEAD(&wimax_dev->id_table_node);
385	__wimax_state_set(wimax_dev, __WIMAX_ST_NULL);
386	mutex_init(&wimax_dev->mutex);
387	mutex_init(&wimax_dev->mutex_reset);
388}
389EXPORT_SYMBOL_GPL(wimax_dev_init);
390
391static const struct nla_policy wimax_gnl_policy[WIMAX_GNL_ATTR_MAX + 1] = {
392	[WIMAX_GNL_RESET_IFIDX] = { .type = NLA_U32, },
393	[WIMAX_GNL_RFKILL_IFIDX] = { .type = NLA_U32, },
394	[WIMAX_GNL_RFKILL_STATE] = {
395		.type = NLA_U32		/* enum wimax_rf_state */
396	},
397	[WIMAX_GNL_STGET_IFIDX] = { .type = NLA_U32, },
398	[WIMAX_GNL_MSG_IFIDX] = { .type = NLA_U32, },
399	[WIMAX_GNL_MSG_DATA] = {
400		.type = NLA_UNSPEC,	/* libnl doesn't grok BINARY yet */
401	},
402};
403
404static const struct genl_ops wimax_gnl_ops[] = {
405	{
406		.cmd = WIMAX_GNL_OP_MSG_FROM_USER,
407		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
408		.flags = GENL_ADMIN_PERM,
409		.doit = wimax_gnl_doit_msg_from_user,
410	},
411	{
412		.cmd = WIMAX_GNL_OP_RESET,
413		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
414		.flags = GENL_ADMIN_PERM,
415		.doit = wimax_gnl_doit_reset,
416	},
417	{
418		.cmd = WIMAX_GNL_OP_RFKILL,
419		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
420		.flags = GENL_ADMIN_PERM,
421		.doit = wimax_gnl_doit_rfkill,
422	},
423	{
424		.cmd = WIMAX_GNL_OP_STATE_GET,
425		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
426		.flags = GENL_ADMIN_PERM,
427		.doit = wimax_gnl_doit_state_get,
428	},
429};
430
431
432static
433size_t wimax_addr_scnprint(char *addr_str, size_t addr_str_size,
434			   unsigned char *addr, size_t addr_len)
435{
436	unsigned int cnt, total;
437
438	for (total = cnt = 0; cnt < addr_len; cnt++)
439		total += scnprintf(addr_str + total, addr_str_size - total,
440				   "%02x%c", addr[cnt],
441				   cnt == addr_len - 1 ? '\0' : ':');
442	return total;
443}
444
445
446/**
447 * wimax_dev_add - Register a new WiMAX device
448 *
449 * @wimax_dev: WiMAX device descriptor (as embedded in your @net_dev's
450 *     priv data). You must have called wimax_dev_init() on it before.
451 *
452 * @net_dev: net device the @wimax_dev is associated with. The
453 *     function expects SET_NETDEV_DEV() and register_netdev() were
454 *     already called on it.
455 *
456 * Registers the new WiMAX device, sets up the user-kernel control
457 * interface (generic netlink) and common WiMAX infrastructure.
458 *
459 * Note that the parts that will allow interaction with user space are
460 * setup at the very end, when the rest is in place, as once that
461 * happens, the driver might get user space control requests via
462 * netlink or from debugfs that might translate into calls into
463 * wimax_dev->op_*().
464 */
465int wimax_dev_add(struct wimax_dev *wimax_dev, struct net_device *net_dev)
466{
467	int result;
468	struct device *dev = net_dev->dev.parent;
469	char addr_str[32];
470
471	d_fnstart(3, dev, "(wimax_dev %p net_dev %p)\n", wimax_dev, net_dev);
472
473	/* Do the RFKILL setup before locking, as RFKILL will call
474	 * into our functions.
475	 */
476	wimax_dev->net_dev = net_dev;
477	result = wimax_rfkill_add(wimax_dev);
478	if (result < 0)
479		goto error_rfkill_add;
480
481	/* Set up user-space interaction */
482	mutex_lock(&wimax_dev->mutex);
483	wimax_id_table_add(wimax_dev);
484	wimax_debugfs_add(wimax_dev);
485
486	__wimax_state_set(wimax_dev, WIMAX_ST_DOWN);
487	mutex_unlock(&wimax_dev->mutex);
488
489	wimax_addr_scnprint(addr_str, sizeof(addr_str),
490			    net_dev->dev_addr, net_dev->addr_len);
491	dev_err(dev, "WiMAX interface %s (%s) ready\n",
492		net_dev->name, addr_str);
493	d_fnend(3, dev, "(wimax_dev %p net_dev %p) = 0\n", wimax_dev, net_dev);
494	return 0;
495
496error_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}
501EXPORT_SYMBOL_GPL(wimax_dev_add);
502
503
504/**
505 * wimax_dev_rm - Unregister an existing WiMAX device
506 *
507 * @wimax_dev: WiMAX device descriptor
508 *
509 * Unregisters a WiMAX device previously registered for use with
510 * wimax_add_rm().
511 *
512 * IMPORTANT! Must call before calling unregister_netdev().
513 *
514 * After this function returns, you will not get any more user space
515 * control requests (via netlink or debugfs) and thus to wimax_dev->ops.
516 *
517 * Reentrancy control is ensured by setting the state to
518 * %__WIMAX_ST_QUIESCING. rfkill operations coming through
519 * wimax_*rfkill*() will be stopped by the quiescing state; ops coming
520 * from the rfkill subsystem will be stopped by the support being
521 * removed by wimax_rfkill_rm().
522 */
523void 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);
528	__wimax_state_change(wimax_dev, __WIMAX_ST_QUIESCING);
529	wimax_debugfs_rm(wimax_dev);
530	wimax_id_table_rm(wimax_dev);
531	__wimax_state_change(wimax_dev, WIMAX_ST_DOWN);
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}
536EXPORT_SYMBOL_GPL(wimax_dev_rm);
537
538
539/* Debug framework control of debug levels */
540struct 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),
547	D_SUBMODULE_DEFINE(stack),
548};
549size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL);
550
551
552static const struct genl_multicast_group wimax_gnl_mcgrps[] = {
553	{ .name = "msg", },
554};
555
556struct genl_family wimax_gnl_family __ro_after_init = {
557	.name = "WiMAX",
558	.version = WIMAX_GNL_VERSION,
559	.hdrsize = 0,
560	.maxattr = WIMAX_GNL_ATTR_MAX,
561	.policy = wimax_gnl_policy,
562	.module = THIS_MODULE,
563	.ops = wimax_gnl_ops,
564	.n_ops = ARRAY_SIZE(wimax_gnl_ops),
565	.mcgrps = wimax_gnl_mcgrps,
566	.n_mcgrps = ARRAY_SIZE(wimax_gnl_mcgrps),
567};
568
569
570
571/* Shutdown the wimax stack */
572static
573int __init wimax_subsys_init(void)
574{
575	int result;
576
577	d_fnstart(4, NULL, "()\n");
578	d_parse_params(D_LEVEL, D_LEVEL_SIZE, wimax_debug_params,
579		       "wimax.debug");
580
581	result = genl_register_family(&wimax_gnl_family);
582	if (unlikely(result < 0)) {
583		pr_err("cannot register generic netlink family: %d\n", result);
584		goto error_register_family;
585	}
586
587	d_fnend(4, NULL, "() = 0\n");
588	return 0;
589
590error_register_family:
591	d_fnend(4, NULL, "() = %d\n", result);
592	return result;
593
594}
595module_init(wimax_subsys_init);
596
597
598/* Shutdown the wimax stack */
599static
600void __exit wimax_subsys_exit(void)
601{
602	wimax_id_table_release();
603	genl_unregister_family(&wimax_gnl_family);
604}
605module_exit(wimax_subsys_exit);
606
607MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>");
608MODULE_DESCRIPTION("Linux WiMAX stack");
609MODULE_LICENSE("GPL");