Subject: Re: [PATCH 02/39] wimax: declarations for the in-kernel WiMAX API

From: Stephen Hemminger <[email-masked]>
Date: Mon, 24 Nov 2008 14:33:26 -0800

On Mon, 24 Nov 2008 13:50:25 -0800
Inaky Perez-Gonzalez <[email-masked]> wrote:

> Declares the main data types and calls for the drivers to integrate
> into the WiMAX stack. Provides usage documentation.
> 
> Signed-off-by: Inaky Perez-Gonzalez <[email-masked]>
> ---
>  include/net/wimax.h |  568 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 568 insertions(+), 0 deletions(-)
>  create mode 100644 include/net/wimax.h
> 
> diff --git a/include/net/wimax.h b/include/net/wimax.h
> new file mode 100644
> index 0000000..06877c7
> --- /dev/null
> +++ b/include/net/wimax.h
> @@ -0,0 +1,568 @@
> +/*
> + * Linux WiMAX
> + * Kernel space API for accessing WiMAX devices
> + *
> + *
> + * Copyright (C) 2007-2008 Intel Corporation <[email-masked]>
> + * Inaky Perez-Gonzalez <[email-masked]>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License version
> + * 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
> + * 02110-1301, USA.
> + *
> + *
> + * The WiMAX stack provides an API for controlling and managing the
> + * system's WiMAX devices. This API affects the control plane; the
> + * data plane is accessed via the network stack (netdev).
> + *
> + * Parts of the WiMAX stack API and notifications are exported to
> + * user space via Generic Netlink. In user space, libwimax (part of
> + * the wimax-tools package) provides a shim layer for accessing those
> + * calls.
> + *
> + * The API is standarized for all WiMAX devices and different drivers
> + * implement the backend support for it. However, device-specific
> + * messaging pipes are provided that can be used to issue commands and
> + * receive notifications in free form.
> + *
> + * Currently the messaging pipes are the only means of control as it
> + * is not known (due to the lack of more devices in the market) what
> + * will be a good abstraction layer. Expect this to change as more
> + * devices show in the market. This API is designed to be growable in
> + * order to address this problem.
> + *
> + * USAGE
> + *
> + * Embed a `struct wimax_dev` in the device's private structure,
> + * initialize and register it. For details, see `struct
> + * wimax_dev`s documentation.
> + *
> + * Once this is done, wimax-tools's libwimax can be used to
> + * communicate with the driver from user space.
> + *
> + * Remember this is a very low level API that will to provide all of
> + * WiMAX features. Other daemons and services running in user space
> + * are the expected clients of it. They offer a higher level API that
> + * applications should use (an example of this is the Intel's WiMAX
> + * Network Service for the i2400m).
> + *
> + * DESIGN
> + *
> + * Although not set on final stone, this very basic interface is
> + * mostly completed. Remember this is meant to grow as new common
> + * operations are decided upon. New operations will be added to the
> + * interface, intent being on keeping backwards compatibility as much
> + * as possible.
> + *
> + * This layer implements a set of calls to control a WiMAX device,
> + * exposing a frontend to the rest of the kernel and user space (via
> + * generic netlink) and a backend implementation in the driver through
> + * function pointers.
> + *
> + * WiMAX devices have a state, and a kernel-only API allows the
> + * drivers to manipulate that state. State transitions are atomic, and
> + * only some of them are allowed (see `enum wimax_st`).
> + *
> + * Most API calls will set the state automatically; in most cases
> + * drivers have to only report state changes due to external
> + * conditions.
> + *
> + * All API operations are 'atomic', serialized thorough a mutex in the
> + * `struct wimax_dev`.
> + *
> + * EXPORTING TO USER SPACE THROUGH GENERIC NETLINK
> + *
> + * The API is exported to user space using generit netlink (other
> + * methods can be added as needed).
> + *
> + * For user-to-kernel traffic we use a function call marshalling
> + * mechanism, where a message X with attributes A, B, C sent from user
> + * space to kernel space means executing the WiMAX API call wimax_X(A,
> + * B, C), sending the results back as a message. For kernel-to-user
> + * (notifications) we use messages over multicast groups. This way we
> + * can have multiple applications monitoring them.
> + *
> + * Each WiMAX network interface gets assigned a unique Generic Netlink
> + * Family ID (named "WiMAX <IFACENAME>").
> + *
> + * This makes it easy (and cheap) to map device to family ID
> + * considering that most deployments will have a single WiMAX device
> + * per system (without any limits on how many WiMAX adaptors per
> + * device might be present). For details, see file
> + * drivers/net/wimax/id-table.c.
> + *
> + * It also makes it easy to do traffic segregation using different
> + * multicast groups, that allow many applications to listen for
> + * notifications without being disrupted by the amount of traffic sent
> + * to other groups.
> + *
> + * User space must explicitly send an open command to the kernel [use
> + * libwimax:wimax_open()] to open a WiMAX handle. The kernel replies
> + * with information about the device that user space will need to talk
> + * to it. Once done, liwimax:wimax_close() releases the handle. No
> + * handle state information is maintained in the kernel (the
> + * connection is stateless).
> + *
> + * TESTING FOR THE INTERFACE AND VERSIONING
> + *
> + * If network interface X is a WiMAX device, there will be a Generic
> + * Netlink family named "WiMAX X" and the device will present a
> + * "wimax" directory in it's network sysfs directory
> + * (/sys/class/net/DEVICE/wimax) [used by HAL].
> + *
> + * The inexistence of any of these means the device does not support
> + * the WiMAX API.
> + *
> + * At open time, an 'open' command is issued; that returns interface
> + * information and with it, the API version the kernel is currently
> + * exporting.
> + *
> + * NOTE: this versioning is a last resort to avoid hard
> + *    incompatibilities. It is the intention of the design of this
> + *    stack not to introduce backward incompatible changes.
> + *
> + * The version code has to fit in one byte (restrictions imposed by
> + * generic netlink); we use `version / 10` for the major version and
> + * `version % 10` for the minor. This gives 9 minors for each major
> + * and 25 majors.
> + *
> + * The version change protocol is as follow:
> + *
> + * - Major versions: needs to be increased if an existing message/API
> + *   call is changed or removed. Doesn't need to be changed if a new
> + *   message is added.
> + *
> + * - Minor verion: needs to be increased if new messages/API calls are
> + *   being added or some other consideration that doesn't impact the
> + *   user-kernel interface too much (like some kind of bug fix) and
> + *   that is kind of left up in the air to common sense.
> + *
> + * User space code should not try to work if the major version it was
> + * compiled for differs from what the kernel offers. As well, if the
> + * minor version of the kernel interface is lower than the one user
> + * space is expecting (the one it was compiled for), the kernel
> + * might be missing API calls; user space shall be ready to handle
> + * said condition.
> + *
> + * libwimax:wimax_open() takes care of checking versions.
> + *
> + * THE OPERATIONS:
> + *
> + * Each operation is defined in its on file (drivers/net/wimax/op-*.c)
> + * for clarity. The parts needed for an operation are:
> + *
> + *  - a function pointer in `struct wimax_dev`: optional, as the
> + *    operation might be implemented by the stack and not by the
> + *    driver.
> + *
> + *    All function pointers are named wimax_dev->op_*(), and drivers
> + *    must implement them except where noted otherwise.
> + *
> + *  - When exported to user space, a `struct nla_policy` to define the
> + *    attributes of the generic netlink command and a `struct genl_ops`
> + *    to define the operation.
> + *
> + * All the declarations for the operation codes (WIMAX_GNL_OP_<NAME>)
> + * and generic netlink attributes (WIMAX_GNL_<NAME>_*) are declared in
> + * include/linux/wimax.h; this file is intended to be cloned by user
> + * space to gain access to those declarations.
> + *
> + * A few caveats to remember:
> + *
> + *  - Need to define attribute numbers starting in 1; otherwise it
> + *    fails.
> + *
> + *  - the `struct genl_family` requires a maximum attribute id; when
> + *    defining the `struct nla_policy` for each message, it has to have
> + *    an array size of WIMAX_GNL_ATTR_MAX+1.
> + *
> + * THE PIPE INTERFACE:
> + *
> + * This interface is kept intentionally simple. The driver can create
> + * any number of pipes through which it can send
> + * messages/notifications to user space. User space can also send
> + * messages through the messaging pipe back to kernel space. See
> + * drivers/net/wimax/op-msg.c for details.
> + *
> + * The kernel-to-user messages are sent with wimax_pipe_msg(), over a
> + * generic netlink multicast group named after the pipe name and
> + * associated to the device's generic netlink family.
> + *
> + * There is always a default pipe created, the messaging pipe. It's up
> + * to the driver to create other pipes (for example, to send a lot of
> + * diagnostics information).
> + *
> + * The bidirectional messaging interface is built over said
> + * "messaging" pipe [which always exists], and the functions
> + * wimax_msg_*() are already setup to work with it. Messages from user
> + * space are sent as unicast and received by the kernel driver through
> + * wimax_dev->op_msg_from_user().
> + *
> + * RFKILL:
> + *
> + * RFKILL support is built into the wimax_dev layer; the driver just
> + * needs to call wimax_report_rfkill_{hw,sw}() to inform of changes in
> + * the hardware or software RF kill switches. When the stack wants to
> + * turn the radio off, it will call wimax_dev->op_rfkill_sw_toggle(),
> + * which the driver implements.
> + *
> + * User space can set the software RF Kill switch by calling
> + * wimax_rfkill().
> + *
> + * The code for now only supports devices that don't require polling;
> + * If the device needs to be polled, create a self-rearming delayed
> + * work struct for polling or look into adding polled support to the
> + * WiMAX stack.
> + *
> + * When initializing the hardware (_probe), after calling
> + * wimax_dev_add(), query the device for it's RF Kill switches status
> + * and feed it back to the WiMAX stack using
> + * wimax_report_rfkill_{hw,sw}(). If any switch is missing, always
> + * report it as ON.
> + *
> + * NOTE: the wimax stack uses an inverted terminology to that of the
> + * RFKILL subsystem:
> + *
> + *  - ON: radio is ON, RFKILL is DISABLED or OFF.
> + *  - OFF: radio is OFF, RFKILL is ENABLED or ON.
> + *
> + * MISCELLANEOUS OPS:
> + *
> + * wimax_reset() can be used to reset the device to power on state; by
> + * default it issues a warm reset that maintains the same device
> + * node. If that is not possible, it falls back to a cold reset
> + * (device reconnect). The driver implements the backend to this
> + * through wimax_dev->op_reset().
> + */
> +
> +#ifndef __NET__WIMAX_H__
> +#define __NET__WIMAX_H__
> +#ifdef __KERNEL__
> +
> +#include <linux/wimax.h>
> +#include <net/genetlink.h>
> +#include <linux/netdevice.h>
> +
> +struct net_device;
> +struct genl_info;
> +struct wimax_dev;
> +struct wimax_pipe;
> +struct input_dev;
> +
> +/**
> + * struct wimax_dev - Generic WiMAX device
> + *
> + * @net_dev: [fill] Pointer to the &struct net_device this WiMAX
> + *     device implements.
> + *
> + * @op_msg_from_user: [fill] Driver-specific operation to
> + *     handle a raw message from user space to the driver. The
> + *     driver can send messages to user space using with
> + *     wimax_msg_to_user().
> + *
> + * @op_rfkill_sw_toggle: [fill] Driver-specific operation to act on
> + *     userspace (or any other agent) requesting the WiMAX device to
> + *     change the RF Kill software switch (WIMAX_RF_ON or
> + *     WIMAX_RF_OFF).
> + *     If such hardware support is not present, it is assumed the
> + *     radio cannot be switched off and it is always on (and the stack
> + *     will error out when trying to switch it off). In such case,
> + *     this function pointer can be left as NULL.
> + *
> + * @op_reset: [fill] Driver specific operation to reset the
> + *     device.
> + *     This operation should always attempt first a warm reset that
> + *     does not disconnect the device from the bus and return 0.
> + *     If that fails, it should resort to some sort of cold or bus
> + *     reset (even if it implies a bus disconnection and device
> + *     dissapearance). In that case, -ENODEV should be returned to
> + *     indicate the device is gone.
> + *     This operation has to be synchronous, and return only when the
> + *     reset is complete. In case of having had to resort to bus/cold
> + *     reset implying a device disconnection, the call is allowed to
> + *     return inmediately.
> + *     See wimax_reset()'s documentation.
> + *
> + * @name: [fill] A way to identify this device. We need to register a
> + *     name with many subsystems (input for RFKILL, workqueue
> + *     creation, etc). We can't use the network device name as that
> + *     might change and in some instances we don't know it yet (until
> + *     we don't call register_netdev()). So we generate an unique one
> + *     using the driver name and device bus id, place it here and use
> + *     it across the board. Recommended naming:
> + *     DRIVERNAME-BUSNAME:BUSID (dev->bus->name, dev->bus_id).
> + *
> + * @id_table_node: [private] link to the list of wimax devices kept by
> + *     id-table.c. Protected by it's own spinlock.
> + *
> + * @pipe_list: [private] List of registered pipes.
> + * 
> + * @pipe_msg: [private] Generic Netlink multicast group for the
> + *     driver to report answers to messages and driver-specific
> + *     reports.
> + *
> + * @mutex: [private] Serializes all concurrent access and execution of
> + *     operations.
> + *
> + * @state: [private] Current state of the WiMAX device.
> + *
> + * @gnl_family: [private] Generic Netlink pipe ID.
> + *
> + * @rfkill: [private] integration into the RF-Kill infrastructure.
> + *
> + * @rfkill_input: [private] virtual input device to process the
> + *     hardware RF Kill switches.
> + *
> + * @rf_sw: [private] State of the software radio switch (OFF/ON)
> + *
> + * @rf_hw: [private] State of the hardware radio switch (OFF/ON)
> + *
> + * Description:
> + * This structure defines a common interface to access all WiMAX
> + * devices from different vendors and provides a common API as well as
> + * a free-form device-specific messaging channel.
> + *
> + * Usage:
> + *  1. Embed a &struct wimax_dev at *the beginning* the network
> + *     device structure so that net_dev->priv points to it.
> + *
> + *  2. memset() it to zero
> + *
> + *  3. Initialize with wimax_dev_init(). This will leave the WiMAX
> + *     device in the %__WIMAX_ST_NULL state.
> + *
> + *  4. Fill all the fields marked with [fill]; once called
> + *     wimax_dev_add(), those fields CANNOT be modified.
> + *
> + *  5. Call wimax_dev_add() *after* registering the network
> + *     device. This will leave the WiMAX device in the %WIMAX_ST_DOWN
> + *     state.
> + *     Protect the driver's net_device->open() against succeeding if
> + *     the wimax device state is lower than %WIMAX_ST_DOWN.
> + *
> + *  6. Select when the device is going to be turned on/initialized;
> + *     for example, it could be initialized on 'ifconfig up' (when the
> + *     netdev op 'open()' is called on the driver).
> + *
> + * When the device is initialized (at `ifconfig up` time, or right
> + * after calling wimax_dev_add() from _probe(), make sure the
> + * following steps are taken
> + *
> + *  a. Move the device to %WIMAX_ST_UNINITIALIZED. This is needed so
> + *     some API calls that shouldn't work until the device is ready
> + *     can be blocked.
> + *
> + *  b. Initialize the device. Make sure to turn the SW radio switch
> + *     off and move the device to state %WIMAX_ST_RADIO_OFF when
> + *     done. When just initialized, a device should be left in RADIO
> + *     OFF state until user space devices to turn it on.
> + *
> + *  c. Query the device for the state of the hardware rfkill switch
> + *     and call wimax_rfkill_report_hw() and wimax_rfkill_report_sw()
> + *     as needed. See below.
> + *
> + * This will populate sysfs entries in the device's directory that tag
> + * it as a device that supports the WiMAX interface (for
> + * userspace). wimax_dev_rm() undoes before unregistering the network
> + * device. Once wimax_dev_add() is called, the driver can get called
> + * on the wimax_dev->op_* function pointers
> + *
> + * CONCURRENCY:
> + *
> + * The stack provides a mutex for each device that will disallow API
> + * calls happening concurrently; thus, op calls into the driver
> + * through the wimax_dev->op*() function pointers will always be
> + * serialized and *never* concurrent.
> + *
> + * For locking, take wimax_dev->mutex is taken; (most) operations in
> + * the API have to check for wimax_dev_is_ready() to return 0 before
> + * continuing (this is done internally).
> + *
> + * REFERENCE COUNTING:
> + *
> + * The WiMAX device is reference counted by the associated network
> + * device. The only operation that can be used to reference the device
> + * is wimax_dev_get_by_genl_info(), and the reference it acquires has
> + * to be released with dev_put(wimax_dev->net_dev).
> + *
> + * RFKILL:
> + *
> + * At startup, both HW and SW radio switchess are assumed to be off.
> + *
> + * At initialization time [after calling wimax_dev_add()], have the
> + * driver query the device for the status of the software and hardware
> + * RF kill switches and call wimax_report_rfkill_hw() and
> + * wimax_rfkill_report_sw() to indicate their state. If any is
> + * missing, just call it to indicate it is ON (radio always on).
> + *
> + * Whenever the driver detects a change in the state of the RF kill
> + * switches, it should call wimax_report_rfkill_hw() or
> + * wimax_report_rfkill_sw() to report it to the stack.
> + */
> +struct wimax_dev {
> +	struct net_device *net_dev;
> +	struct list_head id_table_node;
> +	struct list_head pipe_list;
> +	struct wimax_pipe *pipe_msg;
> +	struct mutex mutex;		/* Protects all members and API calls */
> +	enum wimax_st state;
> +
> +	int (*op_msg_from_user)(struct wimax_dev *wimax_dev,
> +				const void *, size_t,
> +				const struct genl_info *info);
> +	int (*op_rfkill_sw_toggle)(struct wimax_dev *wimax_dev,
> +				   enum wimax_rf_state);
> +	int (*op_reset)(struct wimax_dev *wimax_dev);

Move function pointers separate from data??

> +	struct genl_family gnl_family;
Isn't family for all of wimax not per device?

> +	struct rfkill *rfkill;
> +	struct input_dev *rfkill_input;
> +	unsigned rf_hw:1;
> +	unsigned rf_sw:1;
don't bother with bitfield overhead make them u8

> +	char name[32];
> +};

Why have name in this data structure? Do you handle network device
renames properly?