So you're interested in hacking on NetworkManager?  Here's some cool
stuff you could do...

* Internet Connectivity Detection Enhancements

Current connectivity checking is global, while what we really want is to check
connectivity per-interface and update the global state based on the composite
of each device's state.  Unfortunately that requires two things:

1) latest libsoup and glib for using libsoup connection state signals, which
   allow us to set socket options before the actual connection is made; here
   we'd bind the socket to the specific IP address of the interface we're
   using, and possibly set SO_BINDTODEVICE as well
2) setting /proc/sys/net/ipv4/conf/<iface>/rp_filter to "2" which tells the
   kernel to route the incoming and outgoing packet properly even though the
   interface may not have the necessary routes

The first is the largest obstacle, but ideally we implement this and enable it
when we have the required glib and libsoup versions available.  One other
complication is that this checking should be done during the
NM_DEVICE_STATE_IP_CHECK phase (along with other operations like WiFi hotspot
auto-login) while the current checks are done globally in nm-manager.c, so 
keeping both code paths might be complex.

But ideally, once the device has successfully gotten an IPv4 or IPv6 address, it
should enter the state NM_DEVICE_STATE_IP_CHECK, where a connectivity check is
started.  After the check returns, the device would set a property in
NMDevicePrivate to indicate whether Internet access was successful or not, and
advance to the NM_DEVICE_STATE_ACTIVATED state.

The NMManager object, when determining the overall NM_STATE_* state in the
nm_manager_update_state() function, would query this property and set
NM_STATE_CONNECTED_LOCAL, NM_STATE_CONNECTED_SITE, or NM_STATE_CONNECTED_GLOBAL
based on it and the device's state.


* ADSL support

NetworkManager should natively support ADSL modems using one of the 3 main
connection methods, PPP over ATM (pppoa), PPP over Ethernet (pppoe), or
IP over ATM (ipoatm).  Initial support could be targeted at just pppoa and
pppoe, and there is some code in NetworkManager already for pppoe.  More info
about ADSL configuration on Linux in general is here:

http://atm.eagle-usb.org/wakka.php?wiki=UeagleAtmDoc

Big thanks to Pantelis Koukousoulas for getting ADSL working for PPPoA and PPPoE
methods in the 'adsl' branch in NetworkManager git.  We need more testing, IPv6
PPP support, and also support for multiple ADSL devices (by reading the "atmindex"
attribute from the sysfs directory for the ATM interface on 2.6.38.8 and later
kernels).


* Real Access Point mode support

Now that NetworkManager requires wpa_supplicant 0.7.x or later, we can add
full Access Point (AP) mode support.  NetworkManager currently implements
connection sharing via AdHoc mode support, which has some limitations.  Instead,
we should check whether the wifi device supports AP mode, and if so, use
that mode instead.  wpa_supplicant has support for a "lightweight AP" mode which
we should use.  Witold Sowa started this support a while ago and wrote the new
D-Bus API for wpa_supplicant that makes all this possible, but some NM pieces
are still missing.  If the wifi driver supports AP mode, then in
src/supplicant-manager/ NM should send an AP-mode config instead of sending
the adhoc config.

Note that some devices (airo, ipw2100, ipw2200, iwl3945, iwl4965, atmel, zd1201)
will never support AP mode due to firmware limitations, so we clearly must still
provide Ad-Hoc connection sharing support for those devices and switch between
Ad-Hoc and AP mode depending on device capabilities.


* On-Demand WiFi Scan support

Single-user and embedded devices often use a continuous wifi scan when the
networking configuration interface is open to quickly allow users to find their
wifi network.  NM periodically scans, but this could take as long as 2 mintues
to update the list.  Note that WiFi scans require 2 - 10 seconds to complete,
and during this time normal traffic (video, VOIP, streaming music, downloads,
etc) is not transmitted, so a WiFi scan is a disruptive operation to the user.

A D-Bus method should be added to the NMDeviceWifi device to allow user
applications to request a scan.  This request should be rate-limited to no
more than once every 10 seconds to give time for traffic to resume when the
scan is done, and to lessen the effect of any DDoS by malicious user
applications.  This request should also be restricted by one or more PolicyKit
permissions like org.freedesktop.NetworkManager.network-control.

To begin, a new method definition should be added to the
introspection/nm-device-wifi.xml for a method called "RequestScan" which takes
an argument called "options" of type of "a{sv}".  This argument will be used
later.  An annotation (like the other functions have) should be added so that
the method will be called "impl_device_request_scan".

Next, the corresponding method implementation should be added to
src/nm-device-wifi.c by adding the prototype for impl_device_request_scan
near the top of the file, and implementing it below.  The implementation will
recieve a GHashTable corresponding to the "a{sv}" argument list from the XML
file, but we can ignore that for now.

The incoming request should be authenticated using nm_auth_get_caller_uid()
and additionally starting a PolicyKit authentication check with
with nm_auth_chain_new().  See the function manager_device_disconnect_request()
in src/nm-manager.c for an example of this.

Only after the caller is authorized to scan should the request be checked
against the last scan timestamp, and if the last scan was 10 seconds or more
ago, a new scan should be requested.


* Reconnect to WiFi Networks Only If They Succeeded Once

Currently, NetworkManager will attempt to connect to a previously attempted
WiFi network even if that network was never successfully connected to.  This
causes confusion because sometimes users will randomly try various WiFi networks
hoping to find an open AP, and then wonder why NM tries to reconnect to any of
those APs later when none of them worked originally due to AP-side MAC filtering
or other failures.  What should happen is that NetworkManager should set a flag
on a connection when that connection is successfully connected at least once,
and only autoconnect the wifi network if that flag is present *and* the
NMSettingConnection's 'autoconnect' property is TRUE.

This is a bit tricky because we want to consider all connections that don't have
this flag as having succeeded so that we don't break users' existing connections,
while holding all newly created connections to this policy.  This flag should
be determined and set for all connections, even if we only use it to determine
WiFi behavior for now.

This flag should be a new gboolean property on the NMSettingConnection object
called "connect-success", with a default value of TRUE.  It should default to
TRUE to ensure that existing connections are assumed to have connected
successfully in the past.  New connections created via the AddConnection and
AddAndActivateConnection D-Bus method calls should have the 'connect-success'
property explicitly set to FALSE.  Then, in nm-device.c's device_state_changed()
function where the NM_DEVICE_STATE_ACTIVATED state is handled, the
'connect-success' property should be set to TRUE.

For WiFi then, in nm-device-wifi.c's get_best_auto_connection() method, the
'connect-success' property should be checked and if it is FALSE, the connection
is not considered for auto-activation.


* Implement NM_DEVICE_STATE_DISCONNECTING

To allow for "pre-down" scenarios, this state should be implemented before a
device is taken down while it still has connectivity.  If the device is
taken down because it's ethernet carrier was dropped, or because the WiFi
connection was terminated by the supplicant, this state is pointless and should
be skipped.  But if the user requested a manual "disconnect", or NM is dropping
connections on exit, etc, then this state should be entered.  In the future
this state should hook into a new dispatcher action in src/NetworkManagerUtils.c
to exectue dispatcher scripts during the disconnection, and to wait a limited
amount of time for each script to complete before allowing the device to
proceed to the NM_DEVICE_STATE_DISCONNECTED state, fully implementing pre-down.


* Ethernet Network Auto-detection

There are various methods we can use to autodetect which wired network connection
to use if the user connects to more than one wired network on a frequent basis.
First, 802.1x enterprise switches broadcast frames which can be used to indicate
that the switch supports 802.1x and thus allow NetworkManager to select an
802.1x connection instead of blindly trying DHCP.  Second, NetworkManager could
listen for traffic from a list of MAC addresses.  Third, NetworkManager could
integrate 'arping' functionality to determine if a given IP address matches a
given MAC address, and thus automatically select that connection.  All these
methods can co-exist and be used in parallel.

One small caveat is that MAC addresses are trivial to spoof, so just because
NetworkManager has discovered a certain MAC address does not mean the network
is authenticated; only 802.1x security can assure that a network is the network
the user expects it to be.

In any case, a new 'anchor-addresses' property of type string-array should be
added to the NMSettingWired setting.  Each string element of this property
should be of the format "<ip>/<mac>" or simply "<mac>".  The first format with
an IP address would indicate that "arping"-type behavior should be used to
actively detect the given MAC address; obviously if the given MAC address is
used for passive discovery as well.  The second format simply lists a MAC
address to passively listen for.

One drawback of listening or probing for known MAC addresses is an increase in
latency during connections to ethernet networks.  The probing/listening delay
should be a reasonable amount of time, like 4 - 5 seconds or so, and should
only be used when a visible connection has anchor addresses.

Next a gboolean 'anchor-probing' variable should be added to the
NMDeviceEthernetPrivate structure in src/nm-device-ethernet.c.  This variable
should be set to TRUE whenever the device's carrier turns on *and* there are
visible NMConnections with anchor addresses (ie, connections which are system-
wide or where one of the allowed users of that connection is logged in).  Then
probing and listening are started, which involves opening a low-level socket
on the interface and starting the arping run or listening for MAC addresses.
A timer is also started (don't forget to cache the timer's source ID in the
NMDeviceEthernetPrivate data, and to cancel the timer whenever the device
transitions to any state other than DISCONNECTED).

If a known MAC address is discovered as a result of probing or listening, the
probe/listen socket, timeout, and data are cleaned up, and NetworkManager
would begin activation of the NMConnection that specified the found MAC address
in the 'anchor-addresses' property.  If two or more connections specify the
same MAC address, the connection with the most recent timestamp should be
preferred.

Similarly, if the probing/listening process detects 802.1x frames the device
should be marked as requring 802.1x authentication until the carrier drops.
This would be accomplished by adding a new property to the NMDeviceEthernet
object and exporting that property through the
introspection/nm-device-ethernet.xml file.  This would allow clients like
applets to ensure that users are aware that the device will not allow
un-authenticated connections and that additional credentials are required to
successfully connect to this network.


* VPN re-connect

NM should remember whether a VPN was connected if a connection disconnects
(like WiFi drops out or short carrier drop) or if the laptop goes to sleep.
Upon reconnect, if the same Connection is again active, the previously
connected VPN should be activated again as well.  Basically, don't just drop
the VPN because WiFi choked for 10 seconds, but reconnect the VPN if it was
connected before the drop.


* VPN autoconnect

We should add a property to the NMSettingConnection object in
libnm-util/nm-setting-connection.c called "vpns" that is a string list,
containing a list of Connection UUIDs that should be activated when the base
connection itself is activated.  This will allow a VPN connection to be
started every time another connection is started, so that if you choose you're
always on the VPN in your favorite coffee shop.

The NM_DEVICE_STATE_SECONDARIES state was added specifically for cases like
this.  Thus, after the base device has IP connectivity, but before it has
signaled that it's fully activated, the device should enter the SECONDARIES
state and kick off activation of the given VPN connection.  Only after this
VPN connection has successfully connected should the base device to the
NM_DEVICE_STATE_ACTIVATED state.


* VPN and IPv6

The internal VPN capability should support IPv6.  Essentially, the D-Bus
interface between NetworkManager and the VPN service daemons should be extended
with an IP6Config signal that passes up the IPv6 addressing and routing details
if the VPN daemon is IPv6 capable.  NM should then process those details like it
does with IPv4.  include/NetworkManagerVPN.h should be updated with key/value
pairs defining the various IPv6 attributes much like the IPv4 ones are defined.


* VPN IP Methods

Some VPNs (openvpn with TAP for example) require that DHCP is run on a
pseudo-ethernet device to obtain addressing information.  This is not currently
possible, but NM already has all the code for DHCP.  Thus, a new "method"
key should be defined in include/NetworkManagerVPN.h to allow for DHCP to
be performed if the VPN service daemon requests it in the IP4Config or IP6Config
signals.  A patch here:

http://cgit.freedesktop.org/NetworkManager/NetworkManager/commit/?h=vpn-ip-method

shows that.  In nm-vpn-connection.c, upon receipt of the D-Bus Ip4Config signal
from the VPN plugin, NetworkManager would inspect the "method" property of the
ip4 config dictionary.  If that property was present and set to "auto" then
DHCP would be started using the network interface returned in the dict.  The
nm_vpn_connection_ip4_config_get() function should be split up into two
functions, one containing the existing code for static configuration, and a
second for handling DHCP kickoff.  Minimal parsing of the response should be
handled in the newly reduced nm_vpn_connection_ip4_config_get() function.

To handle DHCP, the NMVPNConnectionPrivate structure should have two members
added:

    NMDHCPManager *dhcp_manager;
    NMDHCPClient  *dhcp4_client;

which would be initialized in the new DHCP handler code split off from
nm_vpn_connection_ip4_config_get().  These new members would be disposed of in
both vpn_cleanup() and dispose(), though remember to stop any ongoing DHCP
transaction when doing so (see dhcp4_cleanup() in nm-device.c for example code).
For basic code to start the DHCP transaction, see dhcp4_start() in nm-device.c
as well.  After calling nm_dhcp_manager_start_ip4() and connecting the signals
to monitor success and failure, the VPN IP4 config handler would simply return
without changing VPN state, unless a failure occurred.

Then, when the DHCP transaction succeeds, which we'd know by checking the
DHCP client state changes in the "state-changed" signal handler we attached to
the DHCP client object returned from nm_dhcp_manager_start_ip4(), the code
would retrieve the completed NMIP4Config object from the DHCP client using the
nm_dhcp_client_get_ip4_config() function, and then proceed to execute
essentially the bottom-half of the existing nm_vpn_connection_ip4_config_get()
function to merge that config with user overrides and apply it to the VPN
tunnel interface.  Other state changes from the DHCP client might trigger a
failure of the VPN connection, just like DHCP timeouts and lease-renewal
failures do for other devices (see dhcp_state_changed() in nm-device.c).


* VPN Service Daemon Secret Requests

In addition to NM asking the service daemons whether more secrets are required,
VPN service daemons (like nm-vpnc-service, nm-openvpn-service, etc) should be
able to ask NetworkManager to provide secrets during the connection attempt. To
do this, the plugin should advertise its ability to handle out-of-band secrets
in its .service file via the key 'async-secrets=true'.  NetworkManager would
check that key and if present activate the VPN as normal, but skip the explicit
NeedSecrets calls.

Instead, a new "SecretsRequired" signal would be added to
introspection/nm-vpn-plugin.xml (and corresponding helper code added to
libnm-glib/nm-vpn-plugin.c) that would be emitted when the plugin determined
that secrets were required.  This signal would have D-Bus signature of "sas"
for the arguments [ <s:uuid>, <as:secrets> ] with the <uuid> obviously being
the connection UUID, and <secrets> being an array of strings of plugin-specific
strings the plugin requires secrets for.  This array of strings would then be
passed as the "hints" parameter in nm-vpn-connection.c when secrets are
requested from agents in a subsequent nm_settings_connection_get_secrets() call.
At this time the agent code only allows one hint per request, so we may need to
extend that to allow more than one hint.

Thus when connecting if the plugin supported async secrets NetworkManager would
still request existing secrets (without interactivity) and send them to the
VPN service daemon in the Connect D-Bus method, then wait for the service daemon
to either request secrets asynchronously via the SecretsRequired signal or to
signal successful connection via the Ip4Config signal.

The vpnc plugin would need to be reworked to open a pipe to vpnc's stdout and
stdin file descriptors to capture any authentication messages, and to match
these messages to known secrets request strings.  When receiving one of these
strings the plugin would determine which secret was being requested and then
emit the SecretsRequired signal to NetworkManager.  This would also imply that
nm-vpnc-service exectutes vpnc with the "--xauth-inter" argument to enable
challenge-response and does not use the "--non-inter" flag which suppresses that
behavior.


* WPS

wpa_supplicant has support for WPS (Wifi Protected Setup, basically Bluetooth-
like PIN codes for setting up a wifi connection) and we should add support for
this to NetworkManager too.  APs that support WPS will say so in their beacon
IEs which are contained in the "WPA" and "RSN" properties of the BSS object
exported by the supplicant, and can be processed in src/nm-wifi-ap.c's
foreach_property_cb() function.  We should add some private fields to the
NMAccessPoint object (defined in nm-wifi-ap.c) to remember whether a specific
AP supports WPS and what WPS methods it supports, and expose that over D-Bus to
GUI clients as well.

There are two common WPS setup methods: PIN and button.  For PIN, the router
either displays a random PIN on an LCD or the router's web UI, or a static PIN
is printed on the router itself.  The user enters that PIN instead of a PSK
when connecting.  For the "button" method, the router has a physical button that
when pushed, allows any client to connect for a short period of time.

We'll then need to add some properties to the NMSettingWirelessSecurity setting
for the WPS PIN code so that when the user enters it through the GUI, it can
be passed back to NM.  And we'll need to figure out some mechanism for passing
back an indication that the user pushed the button on the router for the
pushbutton method.

When connecting to a new access point that supports WPS, the GUI client would
call the AddAndActivateConnection method and wait for NM to request secrets.
NM would determine that the AP supports WPS, and request WPS secrets from the
applet.  The applet would ask the user for a PIN, or to push the button on the
AP, instead of asking for a passphrase or PSK.  When the user has entered the
PIN or pushed the button, the applet returns this information to NM, which
proceeds with the connection.

NM sends the correct wpa_supplicant config for WPS to the supplicant, and waits
for the connection to occur.  WPS can only be used the *first* time, so after a
first successfull connection, NM must request the actual hexadecimal PSK from 
wpa_supplicant via D-Bus, and store that PSK in the connection, clear any WPS
PIN code from the connection, and save the connection to backing storage.

Any applet GUI should also allow the user to enter the PSK instead of completing
association using WPS, since quite a few routers out there are broken, or
because the user has no physical access to the router itself, but has been given
as passphrase/PSK instead.


* Proxies

HTTP and other proxies are per-connection configuration.  It's highly unlikely
that the same proxy you need to use at work is used at home or in a coffee shop.
Thus, it makes sense that which proxy settings to use should be updated when
network connections change.  NetworkManager is a perfect place to do this since
it tracks which network connections are active, and it already queries the
network for automatic proxy configuration via DHCP and WPAD.

We should add a new NMSetting subclass called NMSettingProxy that holds
necessary proxy configuration.  The properties of this setting should be a
superset of what is provided in the Firefox proxy configuration screen and the
various desktop environment proxy configuration tools like the GNOME Network
Proxy control panel; this should include at a minimum:

  method: "auto", "manual", "none"
  default-proxy: string
  default-proxy-port: uint
  default-always: boolean (use default proxy for all protocols)
  ssl-proxy: string
  ssl-proxy-port: uint
  ftp-proxy: string
  ftp-proxy-port: uint
  socks-proxy: string
  socks-proxy-port: uint
  socks-version: uint, either 4 or 5
  no-proxy-for: array of strings (things not to use the proxy for, ie ".foobar.com",
                 "192.168.0.1/24", an IPv6 address, etc)
  pac-url: string (URL of PAC file, overrides DHCP-provided WPAD value)
  (FIXME: proxy authentication?  do we need separate user/pass properties for
    each protocol type?  should NM handle proxy auth or should it be punted
    to each application?)

After completing IP configuration but still during the NM_DEVICE_STATE_IP_CONFIG
activation stage, NetworkManager would merge the automatically supplied proxy
configuration (from DHCP's WPAD option) with user-provided overrides from the
NMSettingProxy and send the results to the system.  The 'default' connection's
proxy configuration would be preferred, so we'd have to update proxy
configuration from nm-policy.c the same time we update DNS information and the
default route.

The merged proxy configuration would then be sent to the system.  There is no
canonical proxy daemon in-use, so we should have plugins (if not separate
shared libraries, then certainly encapsulated source files that implement a
common glib GInterface or are subclasses of eg a parent NMProxyHandler class)
that handle different system proxy handlers.  Some of the proxy handlers are:

  libproxy: need to figure out how it gets proxy info and have NM write merged
             proxy config out to that location
  pacrunner: a D-Bus enabled daemon, NM would call D-Bus methods of the
               pacrunner service with the proxy information
  GNOME/KDE: how do these desktop environments retrieve proxy configuration?


* Better Tablet/Mobile Behavior

There are a few components to this:

1) kernel driver and hardware capabilities: most mobile devices use periodic
background scanning to quickly determine whether a known SSID is available and
notify the connection manager to connect to it.  This typically requires special
capabilities and good powersave/sleep support from the WiFi kernel driver.
There is a background scanning API in nl80211, but we need to determine how many
SSIDs each driver allows for background scanning, and based on that number, give
the driver the most recent N SSIDs.  We still need to periodically wake the
device up and do a full scan just in case the user is near a known SSID that was
not in the N top recently used networks.  This is also beneficial to normal
desktop use-cases.

wpa_supplicant doesn't currently provide an explicit interface for sending SSIDs
to the driver for background scanning, but could simply send a list using
configured networks.  However, NM currently does not send *all* configured
connections' SSIDs to the supplicant, so that's something we should do first
to optimize connection times.  To do this, NM would need to order all networks
using the NM timestamp and convert that into a supplicant priority number, which
would need to be adjusted periodically when the timestamp was updated.  This
would involve tracking each network (exposed by the supplicant as a D-Bus
object) and making sure they were added, deleted, and updated when the backing
NMConnection objects changed.  One complication is that the supplicant
requires secrets for various network types when the network is added via D-Bus,
and NetworkManager might not have those secrets yet.  We may need to modify
the supplicant allow for *all* secrets (PSKs, WEP keys, etc) to be requested
on-demand, not just EAP secrets like 802.1x passwords.  We then need to fix
up the supplicant's D-Bus interface to actually send requests for secrets out
over D-Bus (like wpa_supplicant_eap_param_needed() does for the socket-based
control interface) and to handle the resulting reply from a D-Bus client like
wpa_supplicant_ctrl_iface_ctrl_rsp() does.

With the secrets request stuff and priority handling in place, wpa_supplicant
would control network selection and roaming (based on the priorities NM gave it
of course) instead of NetworkManager itself, and hopefully lead to a faster WiFi
connection process.

2) single-device-at-a-time with overlapping connections: this is also probably
the best route to go for desktop use-cases as well.  Instead of bringing all
available connections up, only bring up the "best" connection at any given
time based on the current priority list (which is rougly Ethernet > WiFi >
3G/Bluetooth/WiMAX).  However, to ensure seamless connectivity, when one
connection begins to degrade, the next-best connection should be started before
the current one is terminated, such that there is a small amount of overlap.
Consequently the same behavior should be used when a better connection becomes
available.  This behavior should be suspended when special connections like
Internet Connection Sharing ones are started, where clearly the priorities
are different (ie, for Mobile Hotspot 3G > WiFi).
