libnm-glib: add nm_device_filter_connections()

This commit is contained in:
Dan Williams 2011-03-10 22:27:10 -06:00
parent fbf118e58e
commit 3320764e1e
8 changed files with 380 additions and 12 deletions

View file

@ -68,6 +68,7 @@ global:
nm_device_ethernet_get_speed;
nm_device_ethernet_get_type;
nm_device_ethernet_new;
nm_device_filter_connections;
nm_device_get_capabilities;
nm_device_get_dhcp4_config;
nm_device_get_dhcp6_config;

View file

@ -21,6 +21,13 @@
* Copyright (C) 2007 - 2011 Red Hat, Inc.
*/
#include <config.h>
#include <string.h>
#include <netinet/ether.h>
#include <nm-setting-connection.h>
#include <nm-setting-bluetooth.h>
#include "nm-device-bt.h"
#include "nm-device-private.h"
#include "nm-object-private.h"
@ -156,6 +163,78 @@ nm_device_bt_get_capabilities (NMDeviceBt *device)
return priv->bt_capabilities;
}
static NMBluetoothCapabilities
get_connection_bt_type (NMConnection *connection)
{
NMSettingBluetooth *s_bt;
const char *bt_type;
s_bt = (NMSettingBluetooth *) nm_connection_get_setting (connection, NM_TYPE_SETTING_BLUETOOTH);
if (!s_bt)
return NM_BT_CAPABILITY_NONE;
bt_type = nm_setting_bluetooth_get_connection_type (s_bt);
g_assert (bt_type);
if (!strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_DUN))
return NM_BT_CAPABILITY_DUN;
else if (!strcmp (bt_type, NM_SETTING_BLUETOOTH_TYPE_PANU))
return NM_BT_CAPABILITY_NAP;
return NM_BT_CAPABILITY_NONE;
}
static GSList *
filter_connections (NMDevice *device, const GSList *connections)
{
GSList *filtered = NULL;
const GSList *iter;
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMConnection *candidate = NM_CONNECTION (iter->data);
NMSettingConnection *s_con;
NMSettingBluetooth *s_bt;
const char *ctype;
const GByteArray *mac;
const char *hw_str;
struct ether_addr *hw_mac;
NMBluetoothCapabilities dev_caps;
NMBluetoothCapabilities bt_type;
s_con = (NMSettingConnection *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_CONNECTION);
g_assert (s_con);
ctype = nm_setting_connection_get_connection_type (s_con);
if (strcmp (ctype, NM_SETTING_BLUETOOTH_SETTING_NAME) != 0)
continue;
s_bt = (NMSettingBluetooth *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_BLUETOOTH);
if (!s_bt)
continue;
/* Check BT address */
hw_str = nm_device_bt_get_hw_address (NM_DEVICE_BT (device));
if (hw_str) {
hw_mac = ether_aton (hw_str);
mac = nm_setting_bluetooth_get_bdaddr (s_bt);
if (mac && hw_mac && memcmp (mac->data, hw_mac->ether_addr_octet, ETH_ALEN))
continue;
}
dev_caps = nm_device_bt_get_capabilities (NM_DEVICE_BT (device));
bt_type = get_connection_bt_type (candidate);
if (!(bt_type & dev_caps))
continue;
/* Connection applies to this device */
filtered = g_slist_prepend (filtered, candidate);
}
return g_slist_reverse (filtered);
}
/************************************************************/
static void
nm_device_bt_init (NMDeviceBt *device)
{
@ -253,17 +332,19 @@ get_property (GObject *object,
}
static void
nm_device_bt_class_init (NMDeviceBtClass *device_class)
nm_device_bt_class_init (NMDeviceBtClass *bt_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (device_class);
GObjectClass *object_class = G_OBJECT_CLASS (bt_class);
NMDeviceClass *device_class = NM_DEVICE_CLASS (bt_class);
g_type_class_add_private (device_class, sizeof (NMDeviceBtPrivate));
g_type_class_add_private (bt_class, sizeof (NMDeviceBtPrivate));
/* virtual methods */
object_class->constructor = constructor;
object_class->dispose = dispose;
object_class->finalize = finalize;
object_class->get_property = get_property;
device_class->filter_connections = filter_connections;
/* properties */

View file

@ -21,6 +21,14 @@
* Copyright (C) 2007 - 2011 Red Hat, Inc.
*/
#include <config.h>
#include <string.h>
#include <netinet/ether.h>
#include <nm-setting-connection.h>
#include <nm-setting-wired.h>
#include <nm-setting-pppoe.h>
#include "nm-device-ethernet.h"
#include "nm-device-private.h"
#include "nm-object-private.h"
@ -186,6 +194,59 @@ nm_device_ethernet_get_carrier (NMDeviceEthernet *device)
return priv->carrier;
}
static GSList *
filter_connections (NMDevice *device, const GSList *connections)
{
GSList *filtered = NULL;
const GSList *iter;
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMConnection *candidate = NM_CONNECTION (iter->data);
NMSettingConnection *s_con;
NMSettingWired *s_wired;
const char *ctype;
gboolean is_pppoe = FALSE;
s_con = (NMSettingConnection *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_CONNECTION);
g_assert (s_con);
ctype = nm_setting_connection_get_connection_type (s_con);
if (!strcmp (ctype, NM_SETTING_PPPOE_SETTING_NAME))
is_pppoe = TRUE;
else if (strcmp (ctype, NM_SETTING_WIRED_SETTING_NAME) != 0)
continue;
s_wired = (NMSettingWired *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_WIRED);
/* Wired setting optional for PPPoE */
if (!is_pppoe && !s_wired)
continue;
if (s_wired) {
const GByteArray *mac;
const char *perm_str;
struct ether_addr *perm_mac;
/* FIXME: filter using s390 subchannels when they are exported over the bus */
/* Check MAC address */
perm_str = nm_device_ethernet_get_permanent_hw_address (NM_DEVICE_ETHERNET (device));
if (perm_str) {
perm_mac = ether_aton (perm_str);
mac = nm_setting_wired_get_mac_address (s_wired);
if (mac && perm_mac && memcmp (mac->data, perm_mac->ether_addr_octet, ETH_ALEN))
continue;
}
}
/* Connection applies to this device */
filtered = g_slist_prepend (filtered, candidate);
}
return g_slist_reverse (filtered);
}
/***********************************************************/
static void
nm_device_ethernet_init (NMDeviceEthernet *device)
{
@ -298,17 +359,19 @@ get_property (GObject *object,
}
static void
nm_device_ethernet_class_init (NMDeviceEthernetClass *device_class)
nm_device_ethernet_class_init (NMDeviceEthernetClass *eth_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (device_class);
GObjectClass *object_class = G_OBJECT_CLASS (eth_class);
NMDeviceClass *device_class = NM_DEVICE_CLASS (eth_class);
g_type_class_add_private (device_class, sizeof (NMDeviceEthernetPrivate));
g_type_class_add_private (eth_class, sizeof (NMDeviceEthernetPrivate));
/* virtual methods */
object_class->constructor = constructor;
object_class->dispose = dispose;
object_class->finalize = finalize;
object_class->get_property = get_property;
device_class->filter_connections = filter_connections;
/* properties */

View file

@ -21,6 +21,13 @@
* Copyright (C) 2008 Novell, Inc.
*/
#include <config.h>
#include <string.h>
#include <nm-setting-connection.h>
#include <nm-setting-gsm.h>
#include <nm-setting-cdma.h>
#include "nm-device-modem.h"
#include "nm-device-private.h"
#include "nm-object-private.h"
@ -110,6 +117,46 @@ nm_device_modem_get_current_capabilities (NMDeviceModem *self)
return priv->current_caps;
}
static GSList *
filter_connections (NMDevice *device, const GSList *connections)
{
GSList *filtered = NULL;
const GSList *iter;
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMConnection *candidate = NM_CONNECTION (iter->data);
NMSettingConnection *s_con;
NMSettingGsm *s_gsm;
NMSettingCdma *s_cdma;
const char *ctype;
NMDeviceModemCapabilities current_caps;
s_con = (NMSettingConnection *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_CONNECTION);
g_assert (s_con);
ctype = nm_setting_connection_get_connection_type (s_con);
if ( strcmp (ctype, NM_SETTING_GSM_SETTING_NAME) != 0
&& strcmp (ctype, NM_SETTING_CDMA_SETTING_NAME) != 0)
continue;
s_gsm = (NMSettingGsm *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_GSM);
s_cdma = (NMSettingCdma *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_CDMA);
if (!s_cdma && !s_gsm)
continue;
current_caps = nm_device_modem_get_current_capabilities (NM_DEVICE_MODEM (device));
if ( (s_gsm && (current_caps & NM_DEVICE_MODEM_CAPABILITY_GSM_UMTS))
|| (s_cdma && (current_caps & NM_DEVICE_MODEM_CAPABILITY_CDMA_EVDO))) {
/* Connection applies to this device */
filtered = g_slist_prepend (filtered, candidate);
}
}
return g_slist_reverse (filtered);
}
/*******************************************************************/
static void
register_for_property_changed (NMDeviceModem *device)
{
@ -194,16 +241,18 @@ dispose (GObject *object)
}
static void
nm_device_modem_class_init (NMDeviceModemClass *device_class)
nm_device_modem_class_init (NMDeviceModemClass *modem_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (device_class);
GObjectClass *object_class = G_OBJECT_CLASS (modem_class);
NMDeviceClass *device_class = NM_DEVICE_CLASS (modem_class);
g_type_class_add_private (device_class, sizeof (NMDeviceModemPrivate));
g_type_class_add_private (modem_class, sizeof (NMDeviceModemPrivate));
/* virtual methods */
object_class->constructor = constructor;
object_class->get_property = get_property;
object_class->dispose = dispose;
device_class->filter_connections = filter_connections;
/**
* NMDeviceModem:modem-capabilities:

View file

@ -21,7 +21,13 @@
* Copyright (C) 2007 - 2011 Red Hat, Inc.
*/
#include <config.h>
#include <string.h>
#include <netinet/ether.h>
#include <nm-setting-connection.h>
#include <nm-setting-wireless.h>
#include <nm-setting-wireless-security.h>
#include "nm-device-wifi.h"
#include "nm-device-private.h"
@ -477,6 +483,90 @@ _nm_device_wifi_set_wireless_enabled (NMDeviceWifi *device,
clean_up_aps (device, TRUE);
}
#define WPA_CAPS (NM_WIFI_DEVICE_CAP_CIPHER_TKIP | \
NM_WIFI_DEVICE_CAP_CIPHER_CCMP | \
NM_WIFI_DEVICE_CAP_WPA | \
NM_WIFI_DEVICE_CAP_RSN)
#define RSN_CAPS (NM_WIFI_DEVICE_CAP_CIPHER_CCMP | NM_WIFI_DEVICE_CAP_RSN)
static gboolean
has_proto (NMSettingWirelessSecurity *s_wsec, const char *proto)
{
int i;
for (i = 0; i < nm_setting_wireless_security_get_num_protos (s_wsec); i++) {
if (g_strcmp0 (proto, nm_setting_wireless_security_get_proto (s_wsec, i)) == 0)
return TRUE;
}
return FALSE;
}
static GSList *
filter_connections (NMDevice *device, const GSList *connections)
{
GSList *filtered = NULL;
const GSList *iter;
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMConnection *candidate = NM_CONNECTION (iter->data);
NMSettingConnection *s_con;
NMSettingWireless *s_wifi;
NMSettingWirelessSecurity *s_wsec;
const char *ctype;
const GByteArray *mac;
const char *hw_str;
struct ether_addr *hw_mac;
NMDeviceWifiCapabilities wifi_caps;
const char *key_mgmt;
s_con = (NMSettingConnection *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_CONNECTION);
g_assert (s_con);
ctype = nm_setting_connection_get_connection_type (s_con);
if (strcmp (ctype, NM_SETTING_WIRELESS_SETTING_NAME) != 0)
continue;
s_wifi = (NMSettingWireless *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_WIRELESS);
if (!s_wifi)
continue;
/* Check MAC address */
hw_str = nm_device_wifi_get_permanent_hw_address (NM_DEVICE_WIFI (device));
if (hw_str) {
hw_mac = ether_aton (hw_str);
mac = nm_setting_wireless_get_mac_address (s_wifi);
if (mac && hw_mac && memcmp (mac->data, hw_mac->ether_addr_octet, ETH_ALEN))
continue;
}
/* Check device capabilities; we assume all devices can do WEP at least */
wifi_caps = nm_device_wifi_get_capabilities (NM_DEVICE_WIFI (device));
s_wsec = (NMSettingWirelessSecurity *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_WIRELESS_SECURITY);
if (s_wsec) {
/* Connection has security, verify it against the device's capabilities */
key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
if ( !g_strcmp0 (key_mgmt, "wpa-none")
|| !g_strcmp0 (key_mgmt, "wpa-psk")
|| !g_strcmp0 (key_mgmt, "wpa-eap")) {
/* Is device only WEP capable? */
if (!(wifi_caps & WPA_CAPS))
continue;
/* Make sure WPA2/RSN-only connections don't get chosen for WPA-only cards */
if (has_proto (s_wsec, "rsn") && !has_proto (s_wsec, "wpa") && !(wifi_caps & RSN_CAPS))
continue;
}
}
/* Connection applies to this device */
filtered = g_slist_prepend (filtered, candidate);
}
return g_slist_reverse (filtered);
}
/**************************************************************/
@ -683,17 +773,19 @@ finalize (GObject *object)
}
static void
nm_device_wifi_class_init (NMDeviceWifiClass *device_class)
nm_device_wifi_class_init (NMDeviceWifiClass *wifi_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (device_class);
GObjectClass *object_class = G_OBJECT_CLASS (wifi_class);
NMDeviceClass *device_class = NM_DEVICE_CLASS (wifi_class);
g_type_class_add_private (device_class, sizeof (NMDeviceWifiPrivate));
g_type_class_add_private (wifi_class, sizeof (NMDeviceWifiPrivate));
/* virtual methods */
object_class->constructor = constructor;
object_class->get_property = get_property;
object_class->dispose = dispose;
object_class->finalize = finalize;
device_class->filter_connections = filter_connections;
/* properties */

View file

@ -21,7 +21,12 @@
* Copyright (C) 2009 Novell, Inc.
*/
#include <config.h>
#include <string.h>
#include <netinet/ether.h>
#include <nm-setting-connection.h>
#include <nm-setting-wimax.h>
#include "nm-device-wimax.h"
#include "nm-object-private.h"
@ -474,6 +479,48 @@ nm_device_wimax_get_bsid (NMDeviceWimax *self)
return priv->bsid;
}
static GSList *
filter_connections (NMDevice *device, const GSList *connections)
{
GSList *filtered = NULL;
const GSList *iter;
for (iter = connections; iter; iter = g_slist_next (iter)) {
NMConnection *candidate = NM_CONNECTION (iter->data);
NMSettingConnection *s_con;
NMSettingWimax *s_wimax;
const char *ctype;
const GByteArray *mac;
const char *hw_str;
struct ether_addr *hw_mac;
s_con = (NMSettingConnection *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_CONNECTION);
g_assert (s_con);
ctype = nm_setting_connection_get_connection_type (s_con);
if (strcmp (ctype, NM_SETTING_WIMAX_SETTING_NAME) != 0)
continue;
s_wimax = (NMSettingWimax *) nm_connection_get_setting (candidate, NM_TYPE_SETTING_WIMAX);
if (!s_wimax)
continue;
/* Check MAC address */
hw_str = nm_device_wimax_get_hw_address (NM_DEVICE_WIMAX (device));
if (hw_str) {
hw_mac = ether_aton (hw_str);
mac = nm_setting_wimax_get_mac_address (s_wimax);
if (mac && hw_mac && memcmp (mac->data, hw_mac->ether_addr_octet, ETH_ALEN))
continue;
}
/* Connection applies to this device */
filtered = g_slist_prepend (filtered, candidate);
}
return g_slist_reverse (filtered);
}
/**************************************************************/
static void
@ -710,6 +757,7 @@ static void
nm_device_wimax_class_init (NMDeviceWimaxClass *wimax_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (wimax_class);
NMDeviceClass *device_class = NM_DEVICE_CLASS (wimax_class);
g_type_class_add_private (wimax_class, sizeof (NMDeviceWimaxPrivate));
@ -717,6 +765,7 @@ nm_device_wimax_class_init (NMDeviceWimaxClass *wimax_class)
object_class->constructor = constructor;
object_class->get_property = get_property;
object_class->dispose = dispose;
device_class->filter_connections = filter_connections;
/* properties */

View file

@ -1395,3 +1395,30 @@ nm_device_disconnect (NMDevice *device,
info);
}
/**
* nm_device_filter_connections:
* @device: an #NMDevice to filter connections for
* @connections: a list of #NMConnection objects to filter
*
* Filters a given list of connections for a given #NMDevice object and return
* connections which may be activated with the device. For example if @device
* is a WiFi device that supports only WEP encryption, the returned list will
* contain any WiFi connections in @connections that allow connection to
* unencrypted or WEP-enabled SSIDs. The returned list will not contain
* Ethernet, Bluetooth, WiFi WPA connections, or any other connection that is
* incompatible with the device.
*
* Returns: (transfer container) (element-type NetworkManager.Connection): a
* list of #NMConnection objects that could be activated with the given @device.
* The elements of the list are owned by their creator and should not be freed
* by the caller, but the returned list itself is owned by the caller and should
* be freed with g_slist_free() when it is no longer required.
**/
GSList *
nm_device_filter_connections (NMDevice *device, const GSList *connections)
{
if (NM_DEVICE_GET_CLASS (device)->filter_connections)
return NM_DEVICE_GET_CLASS (device)->filter_connections (device, connections);
return NULL;
}

View file

@ -73,6 +73,9 @@ typedef struct {
NMDeviceState old_state,
NMDeviceStateReason reason);
GSList * (*filter_connections) (NMDevice *device,
const GSList *connections);
/* Padding for future expansion */
void (*_reserved1) (void);
void (*_reserved2) (void);
@ -108,6 +111,9 @@ void nm_device_disconnect (NMDevice *device,
NMDeviceDeactivateFn callback,
gpointer user_data);
GSList * nm_device_filter_connections (NMDevice *device,
const GSList *connections);
G_END_DECLS
#endif /* NM_DEVICE_H */