Skip to content
No description, website, or topics provided.
Branch: master
Clone or download
Latest commit d9fbf96 Jul 11, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.gitignore Add build/ to .gitignore, so it won't be listed in untracked files. Jan 10, 2019
CMakeLists.txt Add license informations. Jul 11, 2019
KNOWN_ISSUES README KNOWN_ISSUES: update docs and issues May 6, 2019
Makefile
README README: mention our new character escaping... :) May 7, 2019
agh.c Add license informations. Jul 11, 2019
agh.h Add license informations. Jul 11, 2019
agh.init Add license informations. Jul 11, 2019
agh.proto Add license informations. Jul 11, 2019
agh_bearer_setup_helper.sh Add license informations. Jul 11, 2019
agh_commands.c Add license informations. Jul 11, 2019
agh_commands.h Add license informations. Jul 11, 2019
agh_handlers.c Add license informations. Jul 11, 2019
agh_handlers.h Add license informations. Jul 11, 2019
agh_logging.c Add license informations. Jul 11, 2019
agh_logging.h Add license informations. Jul 11, 2019
agh_messages.c Add license informations. Jul 11, 2019
agh_messages.h Add license informations. Jul 11, 2019
agh_mm_handler.c Add license informations. Jul 11, 2019
agh_mm_handler.h Add license informations. Jul 11, 2019
agh_mm_helpers.c Add license informations. Jul 11, 2019
agh_mm_helpers.h Add license informations. Jul 11, 2019
agh_modem.c Add license informations. Jul 11, 2019
agh_modem.h Add license informations. Jul 11, 2019
agh_modem_config.c Add license informations. Jul 11, 2019
agh_modem_config.h Add license informations. Jul 11, 2019
agh_ubus.c Add license informations. Jul 11, 2019
agh_ubus.h Add license informations. Jul 11, 2019
agh_ubus_handler.c Add license informations. Jul 11, 2019
agh_ubus_handler.h Add license informations. Jul 11, 2019
agh_ubus_helpers.c Add license informations. Jul 11, 2019
agh_ubus_helpers.h Add license informations. Jul 11, 2019
agh_ubus_logstream.c Add license informations. Jul 11, 2019
agh_ubus_logstream.h Add license informations. Jul 11, 2019
agh_xmpp.c Add license informations. Jul 11, 2019
agh_xmpp.h Add license informations. Jul 11, 2019
agh_xmpp_caps.c Add license informations. Jul 11, 2019
agh_xmpp_caps.h Add license informations. Jul 11, 2019
agh_xmpp_handlers.c
agh_xmpp_handlers.h Add license informations. Jul 11, 2019
glib.supp glib.supp: add one more suppression (to be evaluated more); Mar 28, 2019
valgrind.sh Initial core cleanup. Switch to GLib's glib.supp Valgrind suppression… Mar 18, 2019
wwan_agh.defaults Add license informations. Jul 11, 2019

README

Welcome!
===============================================================================

Welcome AGH, your management agent for OpenWrt systems, with support for cellular modems management via ModemManager.
Copyright (C) 2018-2019 Meizo Networks.
This software is distributed under the terms of the GPL license, version 2 or later, as published by the Free Software Foundation.

This document aims to be an easy to read starting point, describing AGH.

1. Introduction
===============================================================================
AGH was conceived to be a control agent to be used on an OpenWrt based system, receiving commands over an XMPP connection.
AGH should run on any hardware supported by OpenWrt (or, in other words, in any Linux distribution), provided enough storage and memory resources are available.

2. A quick overview
===============================================================================
Upon startup, AGH performs the following tasks:
1 - If provided with authentication credentials, connects to an XMPP server, and waits for control commands.
The use of TLS / SSL is considered mandatory.
2 - Connects to the uBus ( https://wiki.openwrt.org/doc/techref/ubus ) micro bus architecture, to listen for events, do method calls and so on.
3 - Once an uBus connection is established, connects to the D-Bus messaging bus, via GLib, and waits for ModemManager. Once ModemManager appears on the bus, AGH will try to connect one or more cellular modems, based on its configuration.
4 - Optionally reports on ubus events and system log messages.

AGH tries to converge to a state where the system is connected to the network, can talk to the control XMPP server and access
the uBus messaging bus.
Once this stage is reached, what can be done on the system depends also on the currently employed configuration. If the
OpenWrt rpcd daemon ( https://wiki.openwrt.org/doc/techref/ubus#rpcd ) is installed and running, commands may be
executed on the system, and UCI ( https://wiki.openwrt.org/doc/uci ) configuration values may be retrieved or changed.

AGH has been designed to be event driven when possible, a crucial property on systems where the ordering of events is not
deterministic, also due to interactions with reality (e.g.: cables (un-)plugged, and so on).
Thus, AGH handles uBus restarts, and is able to reconnect to uBus at any time. This is not true for the D-Bus bus.
AGH can interact via uBus with the OpenWrt logd daemon, as shipped with the ubox package. Thus, it is able to stream log
events to the XMPP server.

3. Building AGH
===============================================================================
3.1. Dependencies
===============================================================================
AGH should run properly under both the glibc GNU C library and the musl C library as used in OpenWrt by default.
The following libraries are needed when building AGH: you may use the given URLs as arguments to the "git clone" command.
- UCI configuration library as shipped with OpenWrt: needed to read UCI configuration files internally
http://git.openwrt.org/project/uci.git
- ubox package as shipped with OpenWrt: contains various utility functions needed when interacting with logd or ubus
http://git.openwrt.org/project/ubox.git
and libubox
http://git.openwrt.org/project/libubox.git
- ubus:
http://git.openwrt.org/project/ubus.git
- libstrophe XMPP library: used to talk to XMPP servers
https://github.com/strophe/libstrophe
- libnettle: at the moment, it provides functions to calculate SHA-1 hash for XMPP capabilities
https://git.lysator.liu.se/nettle/nettle.git
- the GLib2 library, containing various utility functions and data structures, extensively used in the whole program:
(note: GObject and GIO are both needed)
https://gitlab.gnome.org/GNOME/glib.git
- libconfig library: used for commands parsing
https://github.com/hyperrealm/libconfig
- ModemManager, and it's libmm-glib library: used to interact with cellular modems
git://anongit.freedesktop.org/ModemManager/ModemManager

Make sure ModemManager can link against some important support libraries:
- libqmi: used to talk with QMI devices
git://anongit.freedesktop.org/libqmi
- libmbim: used to interact with MBIM devices
git://anongit.freedesktop.org/libmbim/libmbim

3.2. Building AGH
===============================================================================
3.2.1. On a Desktop Linux distribution
===============================================================================
The CMake suite is used to build AGH. After moving to the AGH source directory, you may proceed as follows:
$ mkdir build
$ cd build
$ cmake ..
$ make

3.2.2. Preparing your OpenWrt buildroot for AGH
===============================================================================
The OpenWrt core contains some dependencies needed to build AGH, hence it will be sufficient to select them when building your
OpenWrt image. Including the rpcd daemon and its plugins on the image may be useful, and is a requirement if you intend to use
AGH with cellular modems. Infact, AGH will use the file object as provided by rpcd to invoke it's bearers helper setup script.
Other packages are contained in the feeds: they should be selected by the AGH package itself when enabled.
The ModemManager package should be imported manually from the ModemManager OpenWrt integration feed (Mobile Broadband feed), found at:
https://gitlab.freedesktop.org/mobile-broadband/mobile-broadband-openwrt

(e.g.: adding a line containing something like:
src-git mobilebroadband https://gitlab.freedesktop.org/mobile-broadband/mobile-broadband-openwrt
to your OpenWrt's build root directory feeds.conf.default before invoking the ./scripts/feeds script may be sufficient).
Within this feed you will also get libqmi and libmbim.

3.2.2.1. AGH integration in the image
===============================================================================
The AGH source code directory may be moved to a location where the OpenWrt build system will pick it up (e.g.: openwrt/package/network ).
At this point, you should be able to select the AGH package as you do with other packages.

4. Running AGH
===============================================================================
When AGH is installed into the generated OpenWrt image, it should automatically be started when the device boots up.
To prevent this from happening, you can use OpenWrt's service management utilities:
# /etc/init.d/agh enabled && /etc/init.d/agh disable

and, to stop a running instance:
# /etc/init.d/agh stop

When the "agh_xmpp" UCI package is present, AGH will try to connect to an XMPP server to receive commands.
Furthermore, if an "agh_modem" UCI package is found, AGH will handle all the cellular modems exposed by Modemmanager.

5. Configuring AGH
===============================================================================
AGH expects two UCI configuration packages (files) to be present:
1 - agh_xmpp: stores informations about XMPP connectivity;
2 - agh_modem: contains information about modem settings.

The configuration data is read via the UCI library. These files are to be placed in the /etc/config default configuration
directory. 
If one of these files is missing, AGH will not enable the related functionality. The rest of the program should remain
operational. The "uci" command line tool may be used to check for syntax errors and, naturally, to manage these configuration packages.

5.1. XMPP configuration
===============================================================================
This file contains the needed settings to connect to an XMPP server, and to determine which JIDs may send commands to the
program. A agh_xmpp configuration file may look like the following:

config section 'connection'
	option node 'username'
	option domain 'your.domain.com'
	option password 'craccracriccrecr'
	option resource 'agh_agent'
	option tcp_keepalive_interval '1'
	option tcp_keepalive_timeout '60'
	list controller_barejid 'user1@domain1.com'
	list controller_barejid 'user2@domain2.com'
	option ping_interval '120'
	option ping_timeout '10'

5.1.1. XMPP account data
===============================================================================

The following settings are related to our own account, the one AGH should use when authenticating to the XMPP server.

Option: node
UCI type: string
Data type: string
Description:
	This is the node part of the XMPP JID. If the bare JID looks like:
	myname@mydomain.com
	then
	myname
	is the expected value.

Option: domain
UCI type: string
Data type: string
Description:
	This is the domain part of the JID.
	If our JID looks like:
	myname@mydomain.com
	then,
	mydomain.com
	is the value to be expected here.

Option: resource
UCI type: string
Data type: string
Description:
	The resource part of a full JID. If our full JID looks like:
	myname@mydomain.com/tablet
	then
	tablet
	is the value to be expected here.

Option: password
UCI type: string
Data type: string
Description:
	The password used to authenticate with the XMPP server.
	**: [1]

[1]: AGH will try logging in again every 150 second, approximately. This value is currently hard-coded.

5.1.2. Other XMPP settings
===============================================================================

Option: tcp_keepalive_interval
UCI type: string
Data type: integer

Option: tcp_keepalive_timeout
UCI type: string
Data type: integer
Description:
	TCP keepalive interval, and timeout. See libstrophe src/conn.c, xmpp_conn_set_keepalive function for more details.

Option: ping_interval
UCI type: string
Data type: integer
Description:
	Client-side ping interval. AGH will send XMPP ping messages to the server this often.
	See https://xmpp.org/extensions/xep-0199.html
	for more details.
	**: [2]
	**: [3]

Option: ping_timeout
UCI type: string
Data type: integer
Description:
	If no answer is received within this timeout, then the connection is considered broken.

Option: controller_barejid
UCI type: list
Data type: string
Description:
	A list of strings defining "controller accounts": AGH will execute commands sent by those accounts.
	In additions, any of tese accounts will receive AGH events notifications (e.g.: ubus events or system log messages if uBus event reporting or log
	streaming are enabled).
	The bare JID of an account is expected, so a full JID like
	myname@mydomain.com/tablet
	should be entered in it's bare form
	myname@mydomain.com .

Option: altdomain
UCI type: string
Data type: string
Description:
	An alternate domain to use when connecting to an XMPP server.

Option: altport
UCI type: string
Data type: integer
Description:
	Alternate port to use when connecting to an XMPP server, instead of the default 5222.

[2]: at the moment, AGH does not implement the full XMPP capabilities protocol, and will happily send and answer XMPP ping
messages to / from servers that do not advertise this capability. Needs to be fixed, by fully implementing the relevant XEPs, and correctly honouring returned informations.
[3]: it is currently not possible to prevent AGH from answering server-side XMPP ping messages

5.2. Modem configuration
===============================================================================

Here we show an example "agh_modem" configuration file.

config bearer 'default'
	option apn      internet
	option ip_type  IPV4
	option allowed_auth     PAP
	option user     web
	option password web

config modem 'quectel'
	option Equipment_Identifier 861107036962398
	option showchanges 1

config simcard 'mysim'
	option id	'1234567890123456789'
	option PIN_code "2579"

5.2.1. Modem configuration overview
===============================================================================

You may find four kinds of sections in an agh_modem config file:
1 - A global settings section ("settings"):
	Defines some "global settings2, influencing the entire modem handling in the program. Only a single section of this type is
	permitted.
2 - Modem sections ("modem"):
	They define settings that should be applied to a specific modem object as reported by ModemManager. This usually corresponds
	to an hardware modem device. A modem is identified via it's Equipment Identifier (e.g.: the IMEI for 3GPP-based hardware).

3 - SIM card section ("simcard"):
	Contains settings related to a specific SIM card. Those sections are especially useful when working with SIM cards needing to
	be unlocked	via PIN codes. A SIM card is identified via it's SIM Identifier.

4 - Bearer section ("bearer"):
	Settings in these sections are used when a connection needs to be established ("a bearer needs to be created").
	These include connection and authentication details, such as the APN to be used, allowed authentication methods and user credentials when applicable.

In general, all of these sections can have UCI acceptable arbitrary names. An exception is the default bearer section, which
should be named "defaut".
When a string value is used as a boolean, it may have values like "1, "yes" or "on", to indicate a TRUE value, and "0", "no" or
"off" to indicate FALSE ones.
5.2.2. Global settings
===============================================================================
A single global settings section may be present on the "agh_modem" UCI package.

Option: allow_sms
UCI type: string
Data type: string / boolean
Description:
	Defines whether SMS commands should be allowed for this modem. This is meant to prevent accidental exposure of private text
	messages, and should not be tought as a security measure. Infact, the ubser will be able to use uBus calls and system
	commands to access SMS messages.

Option: bearers_check_interval
UCI type: string
Data type: integer
Description:
	Defines how often, in milliseconds, the bearer checker should run.
	Acceptable values range from 5000 to 60000.

5.2.3. Defining modem sections
===============================================================================

If a modem section is present, AGH will apply some settings to that particular modem when it becomes available via
ModemManager.

Option: Equipment_Identifier
UCI type: string
Data type: string
Description:
	The modem Equipment Identifier, uniquely identifying a modem device. For 3GPP-based modems, this is the IMEI number.
	This option is mandatory in a modem section.

Option: enable
UCI type: string
Data type: string / boolean
Description:
	Defines whether this modem should be enabled or not.
	Note that, while the modem won't be enabled and thus no connection will be performed, AGH will still try to get the modem in
	a "disabled" state. This implies that, if a locked SIM is present, AGH will try to unlock it.
	Furthermore, AGH may react to state changes of the modem. In particular, once the modem gets enabled by an external tool such as ModemManager's "mmcli", AGH may try to get it to a connected state if suitable configuration data is found.

Option: expected_simcards
UCI type: list
Data type: string
Description:
	AGH will search for unlocking informations only across the list of specified SIM cards.
	If the SIM card currently in use is unlocked, this option has no effect.

Option: modem_bearers
UCI type: list
Data type: string
Description:
	Bearers to be connected over this modem.
	Only up to 2 bearers may be specified.

Option: showchanges
UCI type: string
Data type: string / boolean
Description:
	If this option is present, property changes regarding the modem will be reported over the XMPP connection (e.g.: signal quality changing over time).

Option: connect
UCI type: string
Data type: string / boolean
Description:
	Defines whether a modem should be connected. AGH will not search for suitable configuration data for this modem,
	and no bearers will be created. AGH will still try to get the modem to an enabled state, so the modem may register to the
	network.

Option: allowed_modes
UCI type: string
Data type: string
Description:
	A comma-separated list of modes the modem is allowed to use (e.g.: "3g,4g").
	**: [1]

Option: preferred_mode
UCI type: string
Data type: string
Description:
	The preferred mode for the modem to use (e.g.: "4g").

[1]: depending on devices (and the firmware they are running), setting modem modes may not work as one would expect; have a
look at ModemManager documentation, and play a little bit with "mmcli" tool, to have an idea on how this may work in your
current scenario. You may also use the "modem" operation's "set_modes" subcommand.

5.2.4. Defining SIM card sections
===============================================================================

Whenever a modem becomes available via ModemManager, AGH tries to enable it. If the modem contains a locked SIM card, AGH tries
to unlock it if it has access to the needed information.
At the moment, the only supported SIM card unlocking method is via PIN code.

The following parameters are valid in a SIM card section.

Option: id
UCI type: string
Data type: string
Description:
	The SIM card ID, an unique identifier for a given SIM card.
	This option is mandatory for each SIM section.
	Retrieving current SIM card's ID may fail on some devices. In those cases, it will not be possible to automatically
	unlock a SIM card.

Option: sim_bearers
UCI type: list
Data type: string
Description:
	A list of bearers that may be used when trying to connect with this SIM card.
	Currently, no more than 2 bearers may be defined.

Option: PIN_code
UCI type: string
Data type: string
Description:
	If the SIM card requires a PIN code to be unlocked, then this code will be used.

5.2.5. Defining bearers
===============================================================================

In this context, a bearer is an entity that can carry data. We inherit our concept of bearer directly from the one exposed by
ModemManager, thus it's advisable to look at its documentation to have a better understanding of what a bearer is, and what it
can be used for.
Most recent modem devices support more than one bearer.

The following parameters are valid for a bearer section:

Option: user
UCI type: string
Data type: string
Description:
	The username to be used when authenticating with the network operator.

Option: password
UCI type: string
Data type: string
Description:
	Password to be used when authenticating with the network operator.

Option: apn
UCI type: string
Data type: string
Description:
	APN (Access Point Name) of the network operator to be used when setting up a cellular connection.
	This option is mandatory in a bearer section.

Option: ip_type
UCI type: string
Data type: string
Description:
	IP family to be used when establishing a connection. Valid string values for this option are:
	- IPV4: an IPV4 connection
	- IPV6: an IPV6 connection
	- IPV4V6: an IPV4V6 connection (maybe tunneled?)
	- none: no IP family

Option: allowed_auth
UCI type: string
Data type: string
Description:
	Allowed authentication method while authenticating to the network operator, in the context of a data connection setup. The
	following strings are considered valid for this option:
	- none: no authentication is allowed
	- PAP: for PAP authentication
	- CHAP: for CHAP authentication
	- MSCHAP: for Microsoft CHAP authentication
	- MSCHAPV2: for Microsoft CHAP authentication, version 2
	- EAP: for EAP authentication

	All of these authentication methods are generally handled entirely in modem firmware: viable options may vary.
	This option is mandatory in a bearer section.

Option: number
UCI type: string
Data type: string
Description:
	Number to be dialed upon connection setup.

Option: allow_roaming
UCI type: string
Data type: string / boolean
Description:
	Defines whether this bearer is allowed to work in a roaming context.

Option: rm_protocol
UCI type: string
Data type: string
Description:
	Defines the bearer RM protocol, for CDMA modems. AGH does not support this kind of modems at the moment.

Option: operator_id
UCI type: string
Data type: string
Description:
	Network operator ID, as exposed by ModemManager, the MMC/MNC pair. This property is used when present in bearers defined in
	the system profiles UCI configuration package ("sys_connection_settings"), expected by AGH in the /usr/share directory.
	When the current SIM card or modem do not have section defined for them in the "agh_modem" configuration file, the existing
	ones do not specify any bearer section names to use, and 	there is no default bearer, then AGH will search for bearers
	sections with this property in the system profiles UCi package. If one matching the current operator's Operator ID is found,
	then AGH will use it to try to connect.
	Retrieving this value from some modems may not be possible. The first found section is used.

Option: metric
UCI type: string
Data type: integer
Description:
	The metric for this bearer.
	**: [1]

Option: override_mtu
UCI type: string
Data type: integer
Description:
	Override the MTU value we receive from modem / ModemManager for this bearer.
	**: [1]

[1]: those options are applied by the AGH OpenWrt netifd protocol handler. AGH passes to the handler all of the section
settings when a new bearer is created. Have a look at the "agh.proto" file in the source directory, installed as
/lib/netifd/proto/agh.sh in an OpenWrt image, to add other options or modify the behaviour of those.

6. An AGH instance lifecycle
===============================================================================

Whenever AGH starts up, it performs the following tasks:
1 - It connects to the uBus system bus if possible, retrying indefinitely otherwise.
2 - If valid XMPP configuration data is present, it tries to connect to an XMPP server, retrying indefinitely upon failure but
waiting some seconds.
3 - If valid modem configuration data is present (an empty configuration file may be enough) and an uBus connection is
available, AGH will try to enable all modems
it can find at startup time, or modems that become available over ModemManager. Those modems may get connected if suitable
configuration data is found.

From a logical perspective, AGH performs some operations independently. As an example, it will try to connect to an XMPP
server regardless of the state of the other tasks (e.g.: if a modem is connected or not). In other words, if a TCP socket can be established to the XMPP server via the libstrophe XMPP library, then
AGH will try connecting to the server and wait for commands, according to the configuration data in the "agh_xmpp"
configuration package.

6.1. uBus
===============================================================================

AGH constantly tries to connect to the uBus daemon, and re-establishes a connection every time it drops (e.g.: because of the
ubus daemon being restarted for some reason).
uBus is infact one of the primary ways to control the system, so AGH was designed with the idea of trying to keep an
uBus connection active all the time.
Whenever an uBus connection is available, AGH uses it to provide the following directly exposed functionalities:
- receiving uBus events as emitted by other processes on the systems (currently AGH is not able to emit events on its own)
- listing objects and invoking methods as exposed by other processes on the system

Furthermore, AGH uses the uBus connection internally:
- to request a file descriptor to which it can connect to receive system log messages (interacting with the log object as
exposed by the logd daemon as shipped with the ubox package)
- to invoke the bearer setup helper script, to inform the Linux OS / the OpenWrt Networking subsystem about the availability
(or unavailability) of a connection.

Should a connection to uBus not be possible for whatever reason, AGH will not be able to provide these functionalities.

6.2. System log messages streaming
===============================================================================

AGH can parse log messages as emitted by the OpenWrt logd logging daemon, as shipped with the ubox package. Once the log
streaming feature has been enabled, AGH will try to keep an open connection to the logging daemon. In particular, every time
the connection to the daemon drops, AGH will repeat the initialization process, involving an uBus request for a file
descriptor from the logd process. Should both the logd and the ubusd daemons be unavailable, AGH will keep trying to establish
an uBus connection first, and a connection with the logging daemon then.
From a logical standpoint, those tasks are performed independently, thus some resources are lost in the process, especially in
terms of CPU cycles. This needs to be fixed by modifying the AGH code to perform only one of these tasks at a time, and passing to the next when appropriate.

6.3. Modem
===============================================================================

AGH can handle cellular modems as exposed by the ModemManager daemon. Should ModemManager be restarted for any reason, AGH will
be able to act accordingly.
Cellular modems are presumed to be "hot-pluggable", so they may be connected or disconnected at any time: a very important
aspect, given the fact that a modem may disappear from the bus for various reasons (e.g.: firmware reboots, insufficient power
available to the device, and so on).

6.3.1. ModemManager connection
===============================================================================

AGH interacts with ModemManager over the D-Bus message bus. To the code within the entire program, D-Bus messages are sent and
received transparently, due to the libmm-glib ModemManager library usage. While we can handle ModemManager appearing and
disappearing from the D-Bus bus gracefully, the same is not true for what pertains our connection with ModemManager itself, the D-bus
bus. If for any reason the D-Bus daemon quits, AGH will be terminated immediately, and will have no chance to shut down
cleanly.

6.3.2. Modems handling
===============================================================================

AGH retains the ModemManager notion of a modem: a stateful device. A modem object may be in one of the following states:

a - Failed state:
	When in this state, a modem is considered to be in an error condition, that can not be recovered, at least not easily.
	Possible reasons for this state include a missing, invalid or failed SIM card.
	If an XMPP connection has been established, AGH will inform all of the accounts specified as controllers about this
	condition. If the reason for the modem being in a failed state is known, it will be reported as well.
	No further action is taken.
b - Unknown state:
	The state of the modem is not known to ModemManager, and subsequently AGH.
	No action is taken.
c - Initializing:
	A modem is in the process of initializing itself. This state is considered to be temporary, hence no action is taken.
d - Locked:
	A modem may enter this state for different reasons, generally involving one or more "locks": restrictions imposed by the
	modem or SIM card.
	A modem may be netowkr-locked, SIM-locked, and so on. One of the most common reasons for a modem to enter thi state, is due
	to the SIM card currently in use requiring a PIN code.
	In such cases, AGH will try to unlock the SIM card by searching for a SIM card section having a SIM Identifier
	corresponding to the one of the current SIM card, and a PIN code. If a list of expected SIM cards is present, AGH will
	restrict its search to this list of SIM cards.
	If an appropriate section is found, then AGH will check if the available PIN unlock retries for this SIM card are more than 2
	(an hard-coded limit). If so, the PIN code will be sent to the SIM card via ModemManager / the modem. A state transition is
	expected to occur upon a successful unlock. Otherwise, this state is considered final, and no further action is taken.
e - Disabling:
	A modem is being disabled. This state is considered temporary, hence no action is taken.
f - Disabled:
	You can say that a modem is in a disabled state once it is ready to be enabled, or when it has been explicitly disabled
	(e.g.: via the "mmcli" tool). AGH tries to enable all disabled modems for which there are no modem sections with an "enable"
	option set to a boolean FALSE value or when shutting down. Furthermore, if a configuration section for this modem exists,
	modes settings are applied by calling libmm-glib's mm_modem_set_current_modes function.
	All of the existing bearers in this modem are deleted asynchronously. This process is expected to be complete when the modem
	reaches a registered state, and so far we never experienced the contrary. Should AGH complain about already existing bearers
	during the configuration / connection process, but they seems "vanished" when you look at the modem via the "mmcli" tool,
 	looking at the code which is run in this state is a good idea.
g - Enabling:
	A modem is in the process of being enabled. This state is considered temporary, hence no action is taken.
h - Enabled:
	A modem is enabled when ready to connect to a cellular network. Messaging and other services may be available via ModemManager.
	This state is considered temporary, at least in 3GPP-based modems, which may automatically register to a network. Until this
	happens, no data connection may be established. Currently, AGH will simply wait for a state change.
i - Searching:
	The modem is searching for a network to register with. This process is not mediated in any way by AGH, which takes no action.
j - Registered:
	A modem is registered to the network, thus it's ready to be used to establish one or more data connections (e.g.: creating
	and connecting bearers).
	When a modem enters this state, AGH looks up its configuration data to determine how to connect it.
	If a "modem" section exists for this modem (e.g.: its Equipment Identifier setting "Equipment_Identifier" corresponds to the
	one of this modem), then modem settings are taken into account. As an example: if the user requested it, AGH will
	start reporting modem properties changes (e.g.: signal quality changes).
k - Connecting:
	The modem is in the process of being connected. A modem may switch to this state from the "registered" one, upon the creation
	and the connection of the first data bearer.
l - Connected:
	This state is entered when at least one data bearer is connected, and left when the last bearer is disconnected.
m - Disconnecting:
	The modem is in the process of being disconnected. This state is considered temporary, hence no action is taken.

Ideally, AGH should always be able to keep in control of the modems present on the system. Still, if for some reason the modem
gets stuck in a state that was considered temporary (e.g.: the "enabled" state), then no other action is performed, leaving the
modem in an undesirable state. This has been observed to happen in some cases.
This will need to be handled. Any ideas, suggestions and patches are very welcome.

6.3.3. Connecting to the network
===============================================================================

Whenever a modem registers to the cellualr network, thus entering the registered state, AGH tries to create and connect one or
more bearers, depending on the current configuration data.
Here we describe the steps involved in this process. Every time one or more bearers are created, AGH will try to connect them.
0 - Prerequisites: AGH should be able to obtain a MMSim object representing the SIM card on this modem from ModemManager, and
successfully reload the "agh_modem" UCI configuration package, should this be needed (e.g.: because we did already search for a
suitable bearer section in the "sys_connection_settings" UCI package, related to "system profiles"). Furthermore,
mm_modem_get_bearer_paths should return no bearer paths (e.g.: no bearers should exist in the modem). If one of those
conditions is not met, then the process will be interrupted.
1 - AGH will search for a configuration section relative to this SIM card (comparing SIM IDs), and for this modem (comparing
Equipment Identifiers).
If a section for the current modem is found and it has a "connect" option set to a boolean FALSE value, then the process is
interrupted.
2 - If a SIM card section exists for the current SIM card, and it has an associated list of bearers, then AGH will use the
refenced bearer sections to create new bearers. The process is considered completed then, and no further steps are taken.
3 - If a modem section exists for the current modem, and it has an associated list of referenced bearers, then this bearers
list will be used. The process is considered completed then, and no further steps are taken.
4 - If a default bearer section exists, it will be used to create a new bearer. The process is considered completed then, and
no further steps are taken.
5 - We switch to the "sys_connection_settings" package, using /usr/share as UCI configuration directory (invoking the
uci_set_confdir function).
If a bearer section with a defined operator ID property exist, for which the operator ID corresponds to the one of the network
operator to which the current SIM authenticated, then that section will be used to create a new bearer.
Only the first match will be considered.

If all of the above steps fail, no bearer is created.
Upon the first successfull 

6.3.3.1. Staying connected
===============================================================================
When the first bearer is successfully created, the "bearer checker" is started.
It periodically checks all the bearers related to all the modems in a connected or registered state, trying to reconnect those
that got disconnected. By default, it will run every 40 seconds, but this may be changed within the settings section of the
"agh_modem" UCI package. The checker stops when there are no more modems exposed by ModemManager, or ModemManager disconnects
from the D-Bus bus.

6.3.3.2. The bearer setup helper
===============================================================================

When a data connection is established via a modem (e.g.: a data bearer has been created and connected), AGH will invoke an
external helper program that should inform the Linux Operating System on which it is running, about the new connection. This
happens even when a data bearer gets disconnected, so the helper program has a chance to clean up the connection. Invocations
are performed via uBus, calling the "exec" method exposed by the rpcd daemon via it's "file" object. If an uBus connection is
not present or the rpcd daemon is not running, the helper script won't be invoked.
An helper script implementation should take into account it may not be invoked when a bearer gets disconnected (e.g.: AGH
crashes or other circumstances where no GLib GObjects signals are received regarding disconnection events). See the
KNOWN_ISSUES file in the source directory for some more details on this issue (GObject leaks).
The helper program receives all of the needed informations to set up a connection via its environment. Some exposed properties
are not strictly necessary in general, still they are provided. 

The following environment variables are provided to the helper program:

a - AGH bearer section settings: here you will find UCI strings settings related to the UCI section from which this bearer was
built.
AGH_PROFILE_BEARER_SECTION
	The name of the section.

AGH_PROFILE_BEARER_allow_roaming
	Related to the "allow_roaming" configuration setting.

AGH_PROFILE_BEARER_allowed_auth
	Related to the "allowed_auth" configuration setting.

AGH_PROFILE_BEARER_apn
	Related to the "apn" configuration setting.

And so on.
This is general, and you will find
AGH_PROFILE_BEARER_<setting_name>
in your environment, where <setting_name> is the name of the UCI string setting to which this environment variable is related.

b - ModemManager bearer properties: while we we recommend you to refer to the ModemManager documentation for more details on
bearer properties, here you'll find a brief description of those we encountered so far.

BEARER_PATH
	The path of the bearer object in the D-Bus bus.

BEARER_INTERFACE
	The Linux interface name to which the bearer is related. This may look like "wwan1".

BEARER_IP_TIMEOUT
	As per ModemManager documentation, this is the maximum time to wait for the bearer to retrieve a valid IP address.

BEARER_IP_FAMILY
	The IP family used with this connection. This variable may assume one of the following values: none, IPV4, IPV6, IPV4V6 or 
	any.

BEARER_IP_METHOD
	Specifies the method that should be used to obtain an IPV4 address. Note that this information may still be useful even when
	dealing with an IPV6 bearer. This variable may assume the following values:
	- unknown
	- ppp: modem expects PPP protocol to be used over a designated serial port
	- static: the program is expected to configure IP parameters on its own, statically
	- DHCP: modem firmware supports DHCP, so a DHCP client may be used to configure the required IP parameters

BEARER_IP_ADDRESS
	IP address the host should use.

BEARER_IP_PREFIX
	IP prefix (netmask) to be used by the host.

BEARER_IP_DNS_1
BEARER_IP_DNS_2
	IP addresses of the primary and secondary DNS servers.

BEARER_IP_GATEWAY
	The host is expected to use this gateway IP address.

BEARER_IP_MTU
	Maximum Transmit Unit value the host is expected to use when sending data via this bearer.

BEARER_IPV6_METHOD
	Method the host is expected to use when obtaining an IPV6 address. This variable may assume one of the following values:
	- unknown
	- ppp: modem expects PPP protocol to be used over one of its serial ports
	- static: the program is expected to configure IP parameters on its own, statically
	- DHCP: modem firmware supports DHCP, so a DHCP client may be used to configure the required IP parameters
	Refer to ModemManager documentation for more details on handling this scenario.

BEARER_IPV6_ADDRESS
	An IPV6 address the host system is expected to use.

BEARER_IPV6_PREFIX
	IPV6 address prefix

BEARER_IP_DNSV6_1
BEARER_IP_DNSV6_2
	IPV6 addresses of the primary and secondary DNS servers the host system may use.

BEARER_IPV6_GATEWAY
	IPV6 address of the gateway the host system is expected to use.

BEARER_IPV6_MTU
	Maximum Transmit Unit expected to be used when sending data via this bearer.

6.3.3.3. The provided bearer setup helper implementation
===============================================================================
AGH ships with a bearer setup helper script, namely "agh_bearer_setup_helper.sh", which is supposed to run in an OpenWrt
system. It should be located in the /opt folder.
**: [1]
Upon startup, it inspects the environment for the required variables, updating it's status directory (usually at
/tmp/bearers_data).
It then invokes the "ifup" command on the "agh_mm" network interface, causing the agh protocol handler to set up network
interfaces. The script assumes a "standard" OpenWrt configuration, after the AGH UCI defaults script has been run.
See https://openwrt.org/docs/guide-developer/uci-defaults
for more informations on UCI defaults.

[1]: the path from which AGH executes the script is currently hard-coded in the agh_mm_call_outside_helper function, found in
agh_modem.c.
[2]: I know I know... how can I explain this better?

6.4. XMPP
===============================================================================

AGH uses the libstrophe XMPP library to talk to an XMPP server. Thanks to libstrophe, AGH supports SSL / TLS (via the
OpenSSL library).
AGH partially implements some XEPs (XMPP Extension Protocols), and in particular:
- XEP-0115: entity capabilities
	This allows AGH to communicate to other XMPP clients about its capabilities; needed to let other clients send AGH
	Message Delivery Receipt requests.
- XEP-0184: Message Delivery Receipts
	AGH will answer to Message Delivery Receipt requests, so a client (like an automated system) can be informed about AGH
	receiving the message.
- XEP-0199: XMPP Ping
	To determine when a connection should be considered broken.
- XEP-0128: Service Discovery Extensions

Due to an incomplete impelemntation of XEP-0115 (entity capabilities), AGH won't act properly in some circumstances. For
instance, it will try to send XMPP Ping messages even when the server did not advertise that XMPP capability.
Furthermore, disconnections from an XMPP server, may cause AGH messages to be lost. Infact, also due to libstrophe not exposing
an interface to do so, we are not able to determine whether a message has been received by the server or not.
When the software determines we are no longer connected, it starts queuing messages internally up to some numerical limit, but
other messages may have already been lost. When the internal queue gets full, all of the queued messages are discarded.
**: [1]

AGH implements XEP-0184, so any message containing Read Receipts Requests tags will be answered accordingly. AGH keeps silent
on invalid commands, so a client may use this information to detect whether a message has been actually received.
To prevent excessive traffic and login attempts, when AGH detects it's not able to get to a connected state, it will pause for
a while. The current implementation of this mechanism is arguable...

Note: AGH will try to avoid eemitting characters that may cause the XMPP stream to be closed. To this end, some characters are
not reported in their original form. Their HEX numerical representation is used instead. See the agh_xmpp_handler_escape
function in agh_xmpp_handlers.c.

[1]: file: agh_xmpp.h
#define AGH_XMPP_MAX_OUTGOING_QUEUED_MESSAGES 300

7. AGH commands format
===============================================================================

AGH uses libconfig to parse its commands. So, each AGH command, should be a valid configuration structure from the perspective
of libconfig.
Furthermore, those commands have been tought to be used by an automated system, which may want to send a bunch of them in a
short time period.
To this end, each command will have an operation ID that the sender can choose, to some extent.
If an AGH message is consequential to a sent command, the automated system can use that ID to correlate the two.

7.1. Command structure
===============================================================================

Wether its received over an XMPP message (in its body) or via other means, an AGH command is a text string.
The string should meet some criteria to be considered a valid command. We will discuss all of them here, both from a libconfig
perspective (i.e.: the string is a configuration snippet), and the AGH one (i.e.: the configuration snippet is a valid command). We
invite you to take a look at the libconfig Configuration Grammar, which can be found here:
https://www.hyperrealm.com/libconfig/libconfig_manual.html#Configuration-File-Grammar

a - Length:
	The overall text length of a command is limited.
	**: [1]
	Operation names (see below) are limited in length as well.
	**: [2]
b - Non-ascii characters should be avoided in commands; AGH will try to convert them to ascii ones.
c - Configuration command structure:
	After successfully parsing the text string, libconfig creates a "root" settings group.
	That group should contain only one element: the "attention keyword" setting.
	** [5]
	The "attention keyword" setting, should be a data structure, namely a list, which should be composed of at least two members:
	an integer value (command ID), and a text string (the requested operation). Any element following these two, is considered an
	argument to the requested operation. Different operations may expect different numbers of arguments, of different data types.
	In particular:
	- a command ID: used to track commands and the messages they may originate from
	**: [3]
	- an operation name: the action to be performed by AGH
	**: [2]
	**: [4]
	- one or more arguments to the operation

So, a valid AGH command may look as follows:

AT = (21, "modem", 0, "plugin")

Where:
- "AT" is the attention keyword
**: [5]
- for a more in-depth explanation about the equal signs and the parentheses you see here, we refer you once again to the
libconfig's Configuration Grammar
- 21 is an arbitrarily choosen integer value, a command ID
- "modem": the operation name; this is a modem-related command

Then we have some arguments:
- the first one is an integer value, 0: in this case it refers to the modem we want to work with
- "plugin" is an argument, a text string.

We are asking AGH to report us the ModemManager plugin being used to handle modem 0 on the system.
Different operations may have compeltely different semantics, still the command structure should be the same.
[1]: file: agh_commands.c
#define AGH_CMD_MAX_TEXT_LEN 400
[2]: file: agh_commands.c
#define AGH_CMD_MAX_OP_NAME_LEN 10
[3]: ID should be a non-zero value
[4]: operation name can not be an empty string
[5]: file: agh_commands.h
#define AGH_CMD_IN_KEYWORD "AT"

7.2. AGH messages
===============================================================================

AGH messages looks like commands from a structure perspective. Still, fields have different meanings.
They may be emitted for different reasons, and amongst them:
- a command may generate one or more messages as results
- events notifications
- to notify the user about error conditions.

7.2.1. AGH messages structure
===============================================================================

The following elements compose an AGH message.
1 - A output keyword: useful to distinguish the type of output to expect in the rest of the message.
**: [1]
If the output is unsolicited (e.g.: was not generated as a consequence of a command), the output keyword is immediately
followed by an exclamation mark ("!").
**: [2]
2 - An equal sign, and parentheses, to mimic the structure of a command.
3 - A response ID: an integer value which should allow the other party to correlate messages to commands.
Infact, all of the messages generated by a command, will have a response ID matching the command ID of the command.
Incremental IDs will be used for unsolicited messages.
**: [3]
4 - A status code: a numerical value describing the status of the operation, or the type of unsolicide output, that generated
this message.
At the moment the software emits messages with status code 200 to describe a non-error condition, 400 otherwise.
**: [6]
The intention was to use status codes similar to the ones used in the HTTP protocol. However, we did not yet define proper
semantics for tese values.
Note that, some events generated from external sources (e.g.: system log messages), may inform the user about error conditions
and other adverse events. Still, AGH will report them with a 200 status code.
5 - Answer body: a text string representing the answer body. This field should be used by the receiver to determine the rest of
the structure of the message (e.g.: how many extra information fields to expect).
In the case of an unsolicited message, this field acts as an "event marker", denoting the kind of event happened.
6 - Extra information fields: a sequence of elements of possibly different types.
The number and type of those elements depends on the operation or event that caused this message to be emitted. Based on the Answer body of the message, it should be possible to know in advance what should be expected in this part of the
message.

As an example, a client may send to AGH the following command, to determine what ModemManager plugin is being used to handle a
specific modem:
AT = (21, "modem", 0, "plugin")
Obtaining an answer like the following one:
IH = ( 21, 200, "Quectel" )

Another command may be used to list the available modems on the system:
AT = (21, "modem")
Yelding to the following answer:
IH = ( 21, 200, "0" )
(i.e.: only one modem, with index 0)
**: [5]

[1]: file: agh_commands.h
#define AGH_CMD_OUT_KEYWORD "IH"
(IH standards for "I am here")
[2]: file: agh_commands.h
#define AGH_CMD_EVENT_KEYWORD AGH_CMD_OUT_KEYWORD"!"
[3]: file: agh_commands.h
#define AGH_CMD_EVENT_MAX_ID AGH_CMD_EVENT_UNKNOWN_ID-1
file: agh_commands.h
#define AGH_CMD_EVENT_UNKNOWN_ID AGH_CMD_ANSWER_STATUS_UNKNOWN
file: agh_commands.h
#define AGH_CMD_ANSWER_STATUS_UNKNOWN 380
( Note: 380 are the first three digits of my phone number, excluding the international calling prefix. :) )
[5]: Why not use integer values for e.g.: modem indexes, in output messages? Because at the moment there isn't a sound way to do so from within
AGH. May we define this a design limitation?
[6]: file: agh_commands.h
#define AGH_CMD_ANSWER_STATUS_OK 200
#define AGH_CMD_ANSWER_STATUS_FAIL 400

7.2.2. DATA messages
===============================================================================

If the first field of the Extra information fields contains the "DATA" text chunk, then the structured part of the message
should end right after this field (e.g.: a closed round bracket should be found).
After that parentheses, arbitrary data may be present, of which the structure should be defined outside of the scope of the
strcutured message.

Some examples of data messages:
1 - A system log message being reported:
IH! = ( 152, 200, "SYSTEM_LOG_MESSAGE", "DATA" )
Thu Oct 25 20:37:39 2018 [1540471059.107] user.notice mrkiko: Hello to everyone reading this document!

8. Implemented operations
===============================================================================

Here we will describe the list of command operations currently supported by AGH.
This section of the document is especially subject to changes as a consequence of AGH development.

At the moment, we can categorise all of the supported operations in three main types:
1. Those interacting with modems (and in future maybe with ModemManager itself)
2. Those interacting with uBus (and from there, with different parts of the system)
3. AGH management operations: at the moment, the only supported one in this category is "quit".

8.1. Modem related operations
===============================================================================

AGH supports some modem related operations. Many more should be added in the future.
You can have a pretty good idea of what they do by looking at the ModemManager API documentation, as distributed with the
ModemManager source code, since most of those operations are centered around ModemManager API calls.

Operation name: modem
Operation arguments: <none>
Description:
	Displays the list of modems exposed by ModemManager.
Answer expected: yes
Error status codes: 400=can not obtain modems list, or no modems
Answer body:
	An index of an available modem.
Extra fields:
	Other modem indexes.

Operation name: modem
Operation arguments:
	arg1: modem index
	arg2: subcommand
Description:
	Performs an action as specified by "subcommand" on a modem specified by its index.
Answer expected: yes
Error status codes: subcommand dependent
Answer body: subcommand dependent
Extra fields: subcommand dependent

Subcommand name: imei
Description: retrieve a modem's IMEI number.

Subcommand name: state
Description: Prints current modem state. The answer looks like:
	IH = ( <id>, <status>, "modem_state", "failed_reason" )

	E.g.: if all is well, you may get an answer like:
	IH = ( 21, 200, "connected", "none" )

Subcommand name: powerstate
Description: retrieve current modem power state
	Example:
	AT = (21, "modem", 1, "powerstate")
	An answer may look like:
	IH = ( 21, 200, "on" )

Subcommand name: supported_caps
Description: Gets the list of combinations of generic families of access technologies supported by this modem.
	Example command:
	AT = (21, "modem", 1, "supported_caps")
	An answer may look like:
	IH = ( 21, 200, "gsm-umts lte gsm-umts, lte" )

Subcommand name: current_caps
Description: Gets the list of generic families of access technologies supported by this modem without a firmware reload or reinitialization.

Subcommand name: manifacturer
Description: returns modem manifacturer.

Subcommand name: model
Description: returns modem device model

Subcommand name: revision
Description: returns modem firmware revision and hardware revision

Subcommand name: drivers
Description: returns the names of the drivers currently handling communications with this modem

Subcommand name: plugin
Description: returns the name of the ModemManager plugin used to handle this modem.
	An example may look like:
	AT = (21, "modem", 1, "plugin")
	Answer:
	IH = ( 21, 200, "Quectel" )

Subcommand name: primary_port
Description: returns the name of the modem primary port; may be a cdc-wdm device in case of QMI, MBIM or NCM modems.

Subcommand name: ports
Description: returns modem ports with known functions, and modem network interfaces

Subcommand name: device
Description: returns the sysfs path of the USB device corresponding to this modem.
	An example looks like:
	AT = (21, "modem", 1, "device")
	Answer:
	IH = ( 21, 200, "/sys/devices/bcma0:4/ehci-platform.0/usb1/1-1" )

Subcommand name: equipment_identifier
Description: returns the equipment identifier, in the case of 3GPP-based modems this is the iMEI number.

Subcommand name: device_identifier
Description: gets a best-effort modem device identifier based on various device informations, like model name, firmware revision, USB/PCI/PCMCIA IDs, and other properties.

Subcommand name: unlock_required
Description: gets current lock state of the modem (e.g.: why is this modem locked? What locks are in effect?).

Subcommand name: unlock_retries
Description: gets available unlock retries.

Subcommand name: max_bearers
Description: returns the maximum number of bearers supported by this modem (definable, and active)

Subcommand name: bearers
Description: returns bearers paths

Subcommand name: numbers
Description: gets the list of numbers (e.g. MSISDN in 3GPP) being currently handled by this SIM / modem.

Subcommand name: get_modes
Description: gets the list of supported mode combinations for this modem, and the currently selected allowed / preferred modes

Subcommand name: set_modes
Description: set modem modes
	This command expects 2 arguments, the first one being the allowed modes, and the second one the preferred mode.
	A set of allowed modes may be expressed as a comma-separated list of mode values.
	an example may look like:
	AT = (21, "modem", 0, "set_modes", "2g,3g,4g", "3g")
	(some event messages are emitted in response to this command).

Subcommand name: bands
Description: gets the list of radio frequency and technology bands supported by the modem, and the ones the modem is currently using to connect to the network.
	An example may look like:
	AT = (21, "modem", 0, "bands")
	Answer:
	IH = ( 21, 200, "egsm dcs utran-1 utran-5 utran-8 eutran-1 eutran-3 eutran-5 eutran-7 eutran-8 eutran-20 eutran-38 eutran-40 eutran-41", "egsm dcs utran-1 utran-5 utran-8 eutran-1 eutran-3 eutran-5 eutran-7 eutran-8 eutran-20 eutran-38 eutran-40 eutran-41" )

Subcommand name: ip_families
Description: gets the list of supported IP families

Subcommand name: signal
Description: gets the signal quality value in percent (0 - 100) of the dominant access technology the modem is using to communicate with the network

Subcommand name: access
Description: gets the current network access technology used by the modem to communicate with the network.

Subcommand name: operator_code
Description: returns network operator code (e.g.: 22250 for Iliad, Italy)



8.2. uBus related operations
===============================================================================

Operation name: ubus
Operation arguments:
	arg1: subcommand
	arg2: subcommand arguments
Description:
	Interact with the uBus micro messaging bus.
Answer expected: yes
Error status codes: subcommand dependent
Answer body: subcommand dependent
Extra fields: subcommand dependent

Subcommand name: list
Description: lists available uBus objects and their properties, such as their methods.

	Example:
	AT = (21, "ubus", "list", "uci")
	Answer:
	IH = ( 21, 200, "DATA" )
	"OBJECT=uci, ID=@4aee48ad"
	"configs":{}
	"get":{"config":"String","section":"String","option":"String","type":"String","match":"Table","ubus_rpc_session":"String"}
	...

Arguments:
	arg1: an ubus object name to restrict returned informations to those pertaining that object;

Subcommand name: call
Description: invoke an uBus method.
	An example looks like:
	AT = (21, "ubus", "call", "file", "exec", "{\"command\":\"ifconfig\",\"params\":[\"wwan0\"]}")
	Answer:
	IH = ( 21, 200, "DATA" )
	{
		"code": 0,
		"stdout": "wwan0     Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  \n          inet addr:10.42.194.151  P-t-P:10.42.194.151  Mask:255.255.255.240\n          inet6 addr:
		fe80::e178:7f04:a58c:bbca\/64 Scope:Link\n          UP POINTOPOINT RUNNING NOARP MULTICAST  MTU:1500  Metric:1\n          RX packets:41019 errors:0 dropped:0 overruns:0 frame:0\n          TX packets:62809 errors:0 dropped:0
		overruns:0 carrier:0\n          collisions:0 txqueuelen:1000 \n          RX bytes:12131746 (11.5 MiB)  TX bytes:7677400 (7.3 MiB)\n\n"
	}

Arguments:
	arg1: the object on which the method should be invoked;
	arg2: the name of the method to invoke;
	arg3: JSON payload with escaping.

Subcommand name: events
Description: this command can be used to manage uBus events notifications reporting.
Arguments:
	arg1: action
	arg2: action arguments
Actions:
	add: adds event masks on which AGH will notify the user
		If no arguments are given, all events will be reported.
		If an argument is supplied to this action, then it's taken to be the event type on which reporting is requested.
		Example:
		AT = (21, "ubus", "events", "add")

		will activate notifications for all events.

		AT = (21, "ubus", "events", "add", "event_name")

		activates reporting only for this kind of event.

	reset: deactivates all notifications for ubus events.

Subcommand name: logstream
Description: activates or deactivates system log messages reporting.
Arguments:
	arg1: a string containing the plus sign ("+") or the minus one ("-"), to respectively activate or deactivate log streaming support.

8.3. AGH related operations
===============================================================================

At the moment, the only AGH related operation is named "quit".

Operation name: quit
Operation arguments: <none>
Description:
	Instructs AGH to quit, exiting. When possible, all modems are disabled upon a normal exit.
	Errors occurring when disabling modems are not handled, potentially leaving them in an unknown state.
Answer expected: no
Error status codes: none expected
Answer body:
	<none>
You can’t perform that action at this time.