Phase 1: register iwd Agent for passphrase prompts
Export net.connman.iwd.Agent at /net/eiwd/agent and register it via AgentManager. RequestPassphrase replies are deferred so the UI can prompt asynchronously; the manager exposes iwd_manager_set_passphrase_handler for the UI layer to plug in. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
73d17ff21c
commit
6ea19e2252
6 changed files with 211 additions and 3 deletions
149
src/iwd/iwd_agent.c
Normal file
149
src/iwd/iwd_agent.c
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
#include "iwd_agent.h"
|
||||
#include "iwd_dbus.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define IWD_AGENT_PATH "/net/eiwd/agent"
|
||||
|
||||
struct _Iwd_Agent
|
||||
{
|
||||
Eldbus_Connection *conn;
|
||||
Eldbus_Service_Interface *svc;
|
||||
Eldbus_Object *am_obj;
|
||||
Eldbus_Proxy *am_proxy;
|
||||
Iwd_Agent_Passphrase_Cb cb;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct _Iwd_Agent_Request
|
||||
{
|
||||
Iwd_Agent *agent;
|
||||
Eldbus_Message *msg; /* original RequestPassphrase message */
|
||||
};
|
||||
|
||||
static Iwd_Agent *_self = NULL; /* one agent per process is plenty */
|
||||
|
||||
/* ----- Method handlers ------------------------------------------------- */
|
||||
|
||||
static Eldbus_Message *
|
||||
_release_cb(const Eldbus_Service_Interface *iface EINA_UNUSED,
|
||||
const Eldbus_Message *msg)
|
||||
{
|
||||
return eldbus_message_method_return_new(msg);
|
||||
}
|
||||
|
||||
static Eldbus_Message *
|
||||
_cancel_cb(const Eldbus_Service_Interface *iface EINA_UNUSED,
|
||||
const Eldbus_Message *msg)
|
||||
{
|
||||
/* iwd dropped the auth attempt; we just ack. */
|
||||
return eldbus_message_method_return_new(msg);
|
||||
}
|
||||
|
||||
static Eldbus_Message *
|
||||
_request_passphrase_cb(const Eldbus_Service_Interface *iface EINA_UNUSED,
|
||||
const Eldbus_Message *msg)
|
||||
{
|
||||
const char *path = NULL;
|
||||
if (!eldbus_message_arguments_get(msg, "o", &path))
|
||||
return eldbus_message_error_new(msg, "net.connman.iwd.Error.InvalidArgs",
|
||||
"Expected object path");
|
||||
if (!_self || !_self->cb)
|
||||
return eldbus_message_error_new(msg, "net.connman.iwd.Agent.Error.Canceled",
|
||||
"No UI handler");
|
||||
|
||||
Iwd_Agent_Request *req = calloc(1, sizeof(*req));
|
||||
req->agent = _self;
|
||||
req->msg = eldbus_message_ref((Eldbus_Message *)msg);
|
||||
_self->cb(_self->data, req, path);
|
||||
/* Deferred reply: returning NULL keeps the message pending. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const Eldbus_Method _methods[] = {
|
||||
{ "Release", NULL,
|
||||
NULL, _release_cb, 0 },
|
||||
{ "RequestPassphrase",
|
||||
ELDBUS_ARGS({ "o", "network" }),
|
||||
ELDBUS_ARGS({ "s", "passphrase" }),
|
||||
_request_passphrase_cb, 0 },
|
||||
{ "Cancel",
|
||||
ELDBUS_ARGS({ "s", "reason" }),
|
||||
NULL, _cancel_cb, 0 },
|
||||
{ NULL, NULL, NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
static const Eldbus_Service_Interface_Desc _iface_desc = {
|
||||
IWD_IFACE_AGENT, _methods, NULL, NULL, NULL, NULL
|
||||
};
|
||||
|
||||
/* ----- Reply / cancel from the UI ------------------------------------- */
|
||||
|
||||
void
|
||||
iwd_agent_reply(Iwd_Agent_Request *req, const char *passphrase)
|
||||
{
|
||||
if (!req) return;
|
||||
Eldbus_Message *r = eldbus_message_method_return_new(req->msg);
|
||||
eldbus_message_arguments_append(r, "s", passphrase ? passphrase : "");
|
||||
eldbus_connection_send(req->agent->conn, r, NULL, NULL, -1);
|
||||
eldbus_message_unref(req->msg);
|
||||
free(req);
|
||||
}
|
||||
|
||||
void
|
||||
iwd_agent_cancel(Iwd_Agent_Request *req)
|
||||
{
|
||||
if (!req) return;
|
||||
Eldbus_Message *e = eldbus_message_error_new(req->msg,
|
||||
"net.connman.iwd.Agent.Error.Canceled",
|
||||
"User canceled");
|
||||
eldbus_connection_send(req->agent->conn, e, NULL, NULL, -1);
|
||||
eldbus_message_unref(req->msg);
|
||||
free(req);
|
||||
}
|
||||
|
||||
/* ----- Registration with iwd ------------------------------------------ */
|
||||
|
||||
static void
|
||||
_on_register(void *data EINA_UNUSED, const Eldbus_Message *msg,
|
||||
Eldbus_Pending *p EINA_UNUSED)
|
||||
{
|
||||
const char *en, *em;
|
||||
if (eldbus_message_error_get(msg, &en, &em))
|
||||
fprintf(stderr, "e_iwd: agent register failed: %s: %s\n", en, em);
|
||||
}
|
||||
|
||||
Iwd_Agent *
|
||||
iwd_agent_new(Eldbus_Connection *conn, Iwd_Agent_Passphrase_Cb cb, void *data)
|
||||
{
|
||||
Iwd_Agent *a = calloc(1, sizeof(*a));
|
||||
if (!a) return NULL;
|
||||
a->conn = conn;
|
||||
a->cb = cb;
|
||||
a->data = data;
|
||||
_self = a;
|
||||
|
||||
a->svc = eldbus_service_interface_register(conn, IWD_AGENT_PATH, &_iface_desc);
|
||||
if (!a->svc) { free(a); _self = NULL; return NULL; }
|
||||
|
||||
a->am_obj = eldbus_object_get(conn, IWD_BUS_NAME, "/net/connman/iwd");
|
||||
if (a->am_obj)
|
||||
{
|
||||
a->am_proxy = eldbus_proxy_get(a->am_obj, IWD_IFACE_AGENT_MANAGER);
|
||||
if (a->am_proxy)
|
||||
eldbus_proxy_call(a->am_proxy, "RegisterAgent", _on_register, NULL, -1,
|
||||
"o", IWD_AGENT_PATH);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
void
|
||||
iwd_agent_free(Iwd_Agent *a)
|
||||
{
|
||||
if (!a) return;
|
||||
if (a->svc) eldbus_service_interface_unregister(a->svc);
|
||||
if (a->am_proxy) eldbus_proxy_unref(a->am_proxy);
|
||||
if (a->am_obj) eldbus_object_unref(a->am_obj);
|
||||
if (_self == a) _self = NULL;
|
||||
free(a);
|
||||
}
|
||||
23
src/iwd/iwd_agent.h
Normal file
23
src/iwd/iwd_agent.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef IWD_AGENT_H
|
||||
#define IWD_AGENT_H
|
||||
|
||||
#include <Eldbus.h>
|
||||
|
||||
typedef struct _Iwd_Agent Iwd_Agent;
|
||||
typedef struct _Iwd_Agent_Request Iwd_Agent_Request;
|
||||
|
||||
/* The UI registers a single handler that is called whenever iwd asks for
|
||||
* a passphrase. The handler must eventually call iwd_agent_reply() or
|
||||
* iwd_agent_cancel() with the request token. */
|
||||
typedef void (*Iwd_Agent_Passphrase_Cb)(void *data,
|
||||
Iwd_Agent_Request *req,
|
||||
const char *network_path);
|
||||
|
||||
Iwd_Agent *iwd_agent_new (Eldbus_Connection *conn,
|
||||
Iwd_Agent_Passphrase_Cb cb, void *data);
|
||||
void iwd_agent_free(Iwd_Agent *a);
|
||||
|
||||
void iwd_agent_reply (Iwd_Agent_Request *req, const char *passphrase);
|
||||
void iwd_agent_cancel(Iwd_Agent_Request *req);
|
||||
|
||||
#endif
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
#include "iwd_dbus.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
|
@ -40,6 +41,7 @@ _emit_managed(Iwd_Dbus *d, Eldbus_Message_Iter *objects)
|
|||
Eldbus_Message_Iter *props;
|
||||
if (!eldbus_message_iter_arguments_get(iface_entry, "sa{sv}", &iface, &props))
|
||||
continue;
|
||||
fprintf(stderr, "e_iwd: %s :: %s\n", path, iface);
|
||||
if (d->cbs.iface_added)
|
||||
d->cbs.iface_added(d->data, path, iface, props);
|
||||
}
|
||||
|
|
@ -53,12 +55,16 @@ _on_get_managed(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending E
|
|||
const char *errname, *errmsg;
|
||||
if (eldbus_message_error_get(msg, &errname, &errmsg))
|
||||
{
|
||||
/* iwd not present yet — name watcher will retry. */
|
||||
fprintf(stderr, "e_iwd: GetManagedObjects error: %s: %s\n", errname, errmsg);
|
||||
return;
|
||||
}
|
||||
Eldbus_Message_Iter *objects;
|
||||
if (!eldbus_message_arguments_get(msg, "a{oa{sa{sv}}}", &objects))
|
||||
return;
|
||||
{
|
||||
fprintf(stderr, "e_iwd: GetManagedObjects: failed to parse top-level dict\n");
|
||||
return;
|
||||
}
|
||||
fprintf(stderr, "e_iwd: GetManagedObjects reply received, walking objects\n");
|
||||
_emit_managed(d, objects);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,13 +14,33 @@ typedef struct _Listener
|
|||
struct _Iwd_Manager
|
||||
{
|
||||
Iwd_Dbus *dbus;
|
||||
Iwd_Agent *agent;
|
||||
Eina_Hash *devices; /* path → Iwd_Device * */
|
||||
Eina_Hash *networks; /* path → Iwd_Network * */
|
||||
Eina_List *listeners; /* Listener * */
|
||||
Iwd_State state;
|
||||
Eina_Bool notify_pending;
|
||||
|
||||
Iwd_Agent_Passphrase_Cb pass_cb;
|
||||
void *pass_data;
|
||||
};
|
||||
|
||||
static void
|
||||
_passphrase_trampoline(void *data, Iwd_Agent_Request *req, const char *path)
|
||||
{
|
||||
Iwd_Manager *m = data;
|
||||
if (m->pass_cb) m->pass_cb(m->pass_data, req, path);
|
||||
else iwd_agent_cancel(req);
|
||||
}
|
||||
|
||||
void
|
||||
iwd_manager_set_passphrase_handler(Iwd_Manager *m, Iwd_Agent_Passphrase_Cb cb, void *data)
|
||||
{
|
||||
if (!m) return;
|
||||
m->pass_cb = cb;
|
||||
m->pass_data = data;
|
||||
}
|
||||
|
||||
static void _recompute_state(Iwd_Manager *m);
|
||||
|
||||
/* ----- listeners ------------------------------------------------------- */
|
||||
|
|
@ -183,7 +203,8 @@ iwd_manager_new(Eldbus_Connection *conn)
|
|||
.iface_added = _on_iface_added,
|
||||
.iface_removed = _on_iface_removed,
|
||||
};
|
||||
m->dbus = iwd_dbus_new(conn, &cbs, m);
|
||||
m->dbus = iwd_dbus_new(conn, &cbs, m);
|
||||
m->agent = iwd_agent_new(conn, _passphrase_trampoline, m);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
|
@ -191,6 +212,7 @@ void
|
|||
iwd_manager_free(Iwd_Manager *m)
|
||||
{
|
||||
if (!m) return;
|
||||
iwd_agent_free(m->agent);
|
||||
iwd_dbus_free(m->dbus);
|
||||
eina_hash_free(m->devices);
|
||||
eina_hash_free(m->networks);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <Eldbus.h>
|
||||
#include <Eina.h>
|
||||
#include "iwd_agent.h"
|
||||
|
||||
typedef enum {
|
||||
IWD_STATE_OFF,
|
||||
|
|
@ -35,4 +36,10 @@ void iwd_manager_listener_del (Iwd_Manager *m, Iwd_Manager_Cb cb, void *data);
|
|||
/* Internal: invoked by sub-objects when their state changes. */
|
||||
void iwd_manager_notify (Iwd_Manager *m);
|
||||
|
||||
/* The UI installs its passphrase prompt here. The handler must
|
||||
* eventually call iwd_agent_reply()/iwd_agent_cancel() with the request. */
|
||||
void iwd_manager_set_passphrase_handler(Iwd_Manager *m,
|
||||
Iwd_Agent_Passphrase_Cb cb,
|
||||
void *data);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ e_iwd_sources = [
|
|||
'e_mod_popup.c',
|
||||
'iwd/iwd_dbus.c',
|
||||
'iwd/iwd_props.c',
|
||||
'iwd/iwd_agent.c',
|
||||
'iwd/iwd_manager.c',
|
||||
'iwd/iwd_device.c',
|
||||
'iwd/iwd_network.c',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue