static NMActStageReturn act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device); NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (device); NMActStageReturn ret; gboolean scanning; ret = NM_DEVICE_CLASS (nm_device_olpc_mesh_parent_class)->act_stage1_prepare (device, reason); if (ret != NM_ACT_STAGE_RETURN_SUCCESS) return ret; /* disconnect companion device, if it is connected */ if (nm_device_get_act_request (NM_DEVICE (priv->companion))) { _LOGI (LOGD_OLPC, "disconnecting companion device %s", nm_device_get_iface (priv->companion)); /* FIXME: VPN stuff here is a bug; but we can't really change API now... */ nm_device_state_changed (NM_DEVICE (priv->companion), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_USER_REQUESTED); _LOGI (LOGD_OLPC, "companion %s disconnected", nm_device_get_iface (priv->companion)); } /* wait with continuing configuration untill the companion device is done scanning */ g_object_get (priv->companion, "scanning", &scanning, NULL); if (scanning) { priv->stage1_waiting = TRUE; return NM_ACT_STAGE_RETURN_POSTPONE; } return NM_ACT_STAGE_RETURN_SUCCESS; }
static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMDeviceOlpcMesh *device = NM_DEVICE_OLPC_MESH (object); _nm_object_ensure_inited (NM_OBJECT (object)); switch (prop_id) { case PROP_HW_ADDRESS: g_value_set_string (value, nm_device_olpc_mesh_get_hw_address (device)); break; case PROP_COMPANION: g_value_set_object (value, nm_device_olpc_mesh_get_companion (device)); break; case PROP_ACTIVE_CHANNEL: g_value_set_uint (value, nm_device_olpc_mesh_get_active_channel (device)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean check_companion_cb (gpointer user_data) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); NMManager *manager; GSList *list; if (priv->companion != NULL) { nm_device_state_changed (NM_DEVICE (user_data), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE); return FALSE; } if (priv->device_added_id != 0) return FALSE; manager = nm_manager_get (); priv->device_added_id = g_signal_connect (manager, "device-added", G_CALLBACK (device_added_cb), self); /* Try to find the companion if it's already known to the NMManager */ for (list = nm_manager_get_devices (manager); list ; list = g_slist_next (list)) { if (is_companion (self, NM_DEVICE (list->data))) break; } g_object_unref (manager); return FALSE; }
static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMDeviceOlpcMesh *device = NM_DEVICE_OLPC_MESH (object); NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (device); struct ether_addr hw_addr; switch (prop_id) { case PROP_HW_ADDRESS: nm_device_olpc_mesh_get_address (device, &hw_addr); g_value_take_string (value, nm_utils_hwaddr_ntoa (&hw_addr, ARPHRD_ETHER)); break; case PROP_COMPANION: if (priv->companion) g_value_set_boxed (value, nm_device_get_path (priv->companion)); else g_value_set_boxed (value, "/"); break; case PROP_ACTIVE_CHANNEL: g_value_set_uint (value, wifi_utils_get_mesh_channel (priv->wifi_data)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void device_added_cb (NMManager *manager, NMDevice *other, gpointer user_data) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); is_companion (self, other); }
static GObject* constructor (GType type, guint n_construct_params, GObjectConstructParam *construct_params) { GObject *object; GObjectClass *klass; NMDeviceOlpcMesh *self; NMDeviceWifiCapabilities caps; klass = G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class); object = klass->constructor (type, n_construct_params, construct_params); if (!object) return NULL; self = NM_DEVICE_OLPC_MESH (object); if (!nm_platform_wifi_get_capabilities (nm_device_get_ifindex (NM_DEVICE (self)), &caps)) { _LOGW (LOGD_HW | LOGD_OLPC, "failed to initialize WiFi driver"); g_object_unref (object); return NULL; } g_signal_connect (nm_manager_get (), "device-added", G_CALLBACK (device_added_cb), self); g_signal_connect (nm_manager_get (), "device-removed", G_CALLBACK (device_removed_cb), self); /* shorter timeout for mesh connectivity */ nm_device_set_dhcp_timeout (NM_DEVICE (self), 20); return object; }
static void dispose (GObject *object) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (object); NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); NMManager *manager; if (priv->dispose_has_run) { G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->dispose (object); return; } priv->dispose_has_run = TRUE; if (priv->wifi_data) wifi_utils_deinit (priv->wifi_data); device_cleanup (self); manager = nm_manager_get (); if (priv->device_added_id) g_signal_handler_disconnect (manager, priv->device_added_id); g_object_unref (manager); G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->dispose (object); }
static NMActStageReturn real_act_stage2_config (NMDevice *dev, NMDeviceStateReason *reason) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (dev); NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); NMConnection *connection; NMSettingOlpcMesh *s_mesh; NMActRequest *req; guint32 channel; const GByteArray *anycast_addr_array; guint8 *anycast_addr = NULL; req = nm_device_get_act_request (dev); g_assert (req); connection = nm_act_request_get_connection (req); g_assert (connection); s_mesh = NM_SETTING_OLPC_MESH (nm_connection_get_setting (connection, NM_TYPE_SETTING_OLPC_MESH)); g_assert (s_mesh); channel = nm_setting_olpc_mesh_get_channel (s_mesh); if (channel != 0) _mesh_set_channel (self, channel); wifi_utils_set_mesh_ssid (priv->wifi_data, nm_setting_olpc_mesh_get_ssid (s_mesh)); anycast_addr_array = nm_setting_olpc_mesh_get_dhcp_anycast_address (s_mesh); if (anycast_addr_array) anycast_addr = anycast_addr_array->data; nm_device_set_dhcp_anycast_address (dev, anycast_addr); return NM_ACT_STAGE_RETURN_SUCCESS; }
static void real_update_hw_address (NMDevice *dev) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (dev); NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); struct ifreq req; int ret, fd; fd = socket (PF_INET, SOCK_DGRAM, 0); if (fd < 0) { nm_log_warn (LOGD_OLPC_MESH, "could not open control socket."); return; } memset (&req, 0, sizeof (struct ifreq)); strncpy (req.ifr_name, nm_device_get_iface (dev), IFNAMSIZ); ret = ioctl (fd, SIOCGIFHWADDR, &req); if (ret) { nm_log_warn (LOGD_OLPC_MESH, "(%s): error getting hardware address: %d", nm_device_get_iface (dev), errno); goto out; } if (memcmp (&priv->hw_addr, &req.ifr_hwaddr.sa_data, sizeof (struct ether_addr))) { memcpy (&priv->hw_addr, &req.ifr_hwaddr.sa_data, sizeof (struct ether_addr)); g_object_notify (G_OBJECT (dev), NM_DEVICE_OLPC_MESH_HW_ADDRESS); } out: close (fd); }
static NMActStageReturn act_stage2_config (NMDevice *device, NMDeviceStateReason *reason) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device); NMConnection *connection; NMSettingOlpcMesh *s_mesh; guint32 channel; GBytes *ssid; const char *anycast_addr; connection = nm_device_get_connection (device); g_assert (connection); s_mesh = nm_connection_get_setting_olpc_mesh (connection); g_assert (s_mesh); channel = nm_setting_olpc_mesh_get_channel (s_mesh); if (channel != 0) _mesh_set_channel (self, channel); ssid = nm_setting_olpc_mesh_get_ssid (s_mesh); nm_platform_mesh_set_ssid (nm_device_get_ifindex (device), g_bytes_get_data (ssid, NULL), g_bytes_get_size (ssid)); anycast_addr = nm_setting_olpc_mesh_get_dhcp_anycast_address (s_mesh); nm_device_set_dhcp_anycast_address (device, anycast_addr); return NM_ACT_STAGE_RETURN_SUCCESS; }
static void device_removed_cb (NMManager *manager, NMDevice *other, gpointer user_data) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); if (other == NM_DEVICE_OLPC_MESH_GET_PRIVATE (self)->companion) companion_cleanup (self); }
static gboolean real_is_up (NMDevice *device) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device); NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); return priv->up; }
static gboolean real_bring_up (NMDevice *dev) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (dev); NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); priv->up = TRUE; return TRUE; }
static gboolean companion_scan_allowed_cb (NMDeviceWifi *companion, gpointer user_data) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); NMDeviceState state = nm_device_get_state (NM_DEVICE (self)); /* Don't allow the companion to scan while configuring the mesh interface */ return (state < NM_DEVICE_STATE_PREPARE) || (state > NM_DEVICE_STATE_IP_CONFIG); }
static void state_changed (NMDevice *device, NMDeviceState new_state, NMDeviceState old_state, NMDeviceStateReason reason) { if (new_state == NM_DEVICE_STATE_UNAVAILABLE) find_companion (NM_DEVICE_OLPC_MESH (device)); }
static void constructed (GObject *object) { NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (object); G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->constructed (object); priv->proxy = _nm_object_new_proxy (NM_OBJECT (object), NULL, NM_DBUS_INTERFACE_DEVICE_OLPC_MESH); register_properties (NM_DEVICE_OLPC_MESH (object)); }
static gboolean companion_autoconnect_allowed_cb (NMDeviceWifi *companion, gpointer user_data) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); NMDeviceState state = nm_device_get_state (NM_DEVICE (self)); /* Don't allow the companion to autoconnect while a mesh connection is * active */ return (state < NM_DEVICE_STATE_PREPARE) || (state > NM_DEVICE_STATE_ACTIVATED); }
static void dispose (GObject *object) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (object); companion_cleanup (self); g_signal_handlers_disconnect_by_func (nm_manager_get (), G_CALLBACK (device_added_cb), self); g_signal_handlers_disconnect_by_func (nm_manager_get (), G_CALLBACK (device_removed_cb), self); G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class)->dispose (object); }
static gboolean companion_scan_allowed_cb (NMDeviceWifi *companion, gpointer user_data) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); NMDeviceState state; g_object_get (G_OBJECT (self), NM_DEVICE_INTERFACE_STATE, &state, NULL); /* Don't allow the companion to scan while configuring the mesh interface */ return (state < NM_DEVICE_STATE_PREPARE) || (state > NM_DEVICE_STATE_IP_CONFIG); }
static gboolean companion_autoconnect_allowed_cb (NMDeviceWifi *companion, gpointer user_data) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); NMDeviceState state; g_object_get (G_OBJECT (self), NM_DEVICE_INTERFACE_STATE, &state, NULL); /* Don't allow the companion to autoconnect while a mesh connection is * active */ return (state < NM_DEVICE_STATE_PREPARE) || (state > NM_DEVICE_STATE_ACTIVATED); }
static gboolean is_available (NMDevice *device) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device); if (!NM_DEVICE_OLPC_MESH_GET_PRIVATE (self)->companion) { _LOGD (LOGD_WIFI, "not available because companion not found"); return FALSE; } return TRUE; }
static void device_added_cb (NMManager *manager, NMDevice *other, gpointer user_data) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); if (!priv->companion && check_companion (self, other)) { nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_NONE); nm_device_remove_pending_action (NM_DEVICE (self), "waiting for companion", TRUE); } }
static void companion_notify_cb (NMDeviceWifi *companion, GParamSpec *pspec, gpointer user_data) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); gboolean scanning; if (!priv->stage1_waiting) return; g_object_get (companion, "scanning", &scanning, NULL); if (!scanning) { priv->stage1_waiting = FALSE; nm_device_activate_schedule_stage2_device_config (NM_DEVICE (self)); } }
static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { NMDeviceOlpcMesh *device = NM_DEVICE_OLPC_MESH (object); NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (device); switch (prop_id) { case PROP_COMPANION: nm_utils_g_value_set_object_path (value, priv->companion); break; case PROP_ACTIVE_CHANNEL: g_value_set_uint (value, nm_platform_mesh_get_channel (NM_PLATFORM_GET, nm_device_get_ifindex (NM_DEVICE (device)))); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
/* disconnect from mesh if someone starts using the companion */ static void companion_state_changed_cb (NMDeviceWifi *companion, NMDeviceState state, NMDeviceState old_state, NMDeviceStateReason reason, gpointer user_data) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (user_data); NMDeviceState self_state = nm_device_get_state (NM_DEVICE (self)); if ( self_state < NM_DEVICE_STATE_PREPARE || self_state > NM_DEVICE_STATE_ACTIVATED || state < NM_DEVICE_STATE_PREPARE || state > NM_DEVICE_STATE_ACTIVATED) return; _LOGD (LOGD_OLPC, "disconnecting mesh due to companion connectivity"); /* FIXME: VPN stuff here is a bug; but we can't really change API now... */ nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_USER_REQUESTED); }
static GObject* constructor (GType type, guint n_construct_params, GObjectConstructParam *construct_params) { GObject *object; GObjectClass *klass; NMDeviceOlpcMesh *self; NMDeviceOlpcMeshPrivate *priv; klass = G_OBJECT_CLASS (nm_device_olpc_mesh_parent_class); object = klass->constructor (type, n_construct_params, construct_params); if (!object) return NULL; self = NM_DEVICE_OLPC_MESH (object); priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self); nm_log_dbg (LOGD_HW | LOGD_OLPC_MESH, "(%s): kernel ifindex %d", nm_device_get_iface (NM_DEVICE (self)), nm_device_get_ifindex (NM_DEVICE (self))); priv->wifi_data = wifi_utils_init (nm_device_get_iface (NM_DEVICE (self)), nm_device_get_ifindex (NM_DEVICE (self)), FALSE); if (priv->wifi_data == NULL) { nm_log_warn (LOGD_HW | LOGD_OLPC_MESH, "(%s): failed to initialize WiFi driver", nm_device_get_iface (NM_DEVICE (self))); g_object_unref (object); return NULL; } /* shorter timeout for mesh connectivity */ nm_device_set_dhcp_timeout (NM_DEVICE (self), 20); return object; }
static void state_changed_cb (NMDevice *device, NMDeviceState state, gpointer user_data) { NMDeviceOlpcMesh *self = NM_DEVICE_OLPC_MESH (device); switch (state) { case NM_DEVICE_STATE_UNMANAGED: break; case NM_DEVICE_STATE_UNAVAILABLE: /* If transitioning to UNAVAILBLE and the companion device is known then * transition to DISCONNECTED otherwise wait for our companion. */ g_idle_add (check_companion_cb, self); break; case NM_DEVICE_STATE_ACTIVATED: break; case NM_DEVICE_STATE_FAILED: break; case NM_DEVICE_STATE_DISCONNECTED: break; default: break; } }
static const char * get_hw_address (NMDevice *device) { return nm_device_olpc_mesh_get_hw_address (NM_DEVICE_OLPC_MESH (device)); }
static void real_take_down (NMDevice *dev) { device_cleanup (NM_DEVICE_OLPC_MESH (dev)); }