|
@@ -0,0 +1,214 @@
|
|
|
+/*
|
|
|
+ * Python bindings for wpa_ctrl (wpa_supplicant/hostapd control interface)
|
|
|
+ * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
|
|
|
+ *
|
|
|
+ * This software may be distributed under the terms of the BSD license.
|
|
|
+ * See README for more details.
|
|
|
+ */
|
|
|
+
|
|
|
+#include <Python.h>
|
|
|
+#include <structmember.h>
|
|
|
+
|
|
|
+#include "wpa_ctrl.h"
|
|
|
+
|
|
|
+
|
|
|
+struct wpaspy_obj {
|
|
|
+ PyObject_HEAD
|
|
|
+ struct wpa_ctrl *ctrl;
|
|
|
+ int attached;
|
|
|
+};
|
|
|
+
|
|
|
+static PyObject *wpaspy_error;
|
|
|
+
|
|
|
+
|
|
|
+static int wpaspy_open(struct wpaspy_obj *self, PyObject *args)
|
|
|
+{
|
|
|
+ const char *path;
|
|
|
+
|
|
|
+ if (!PyArg_ParseTuple(args, "s", &path))
|
|
|
+ return -1;
|
|
|
+ self->ctrl = wpa_ctrl_open(path);
|
|
|
+ if (self->ctrl == NULL)
|
|
|
+ return -1;
|
|
|
+ self->attached = 0;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static void wpaspy_close(struct wpaspy_obj *self)
|
|
|
+{
|
|
|
+ if (self->ctrl) {
|
|
|
+ if (self->attached)
|
|
|
+ wpa_ctrl_detach(self->ctrl);
|
|
|
+ wpa_ctrl_close(self->ctrl);
|
|
|
+ self->ctrl = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (self->ob_type)
|
|
|
+ self->ob_type->tp_free((PyObject *) self);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static PyObject * wpaspy_request(struct wpaspy_obj *self, PyObject *args)
|
|
|
+{
|
|
|
+ const char *cmd;
|
|
|
+ char buf[4096];
|
|
|
+ size_t buflen;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (!PyArg_ParseTuple(args, "s", &cmd))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ buflen = sizeof(buf) - 1;
|
|
|
+ ret = wpa_ctrl_request(self->ctrl, cmd, strlen(cmd), buf, &buflen,
|
|
|
+ NULL);
|
|
|
+ if (ret == -2) {
|
|
|
+ PyErr_SetString(wpaspy_error, "Request timed out");
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ if (ret) {
|
|
|
+ PyErr_SetString(wpaspy_error, "Request failed");
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ buf[buflen] = '\0';
|
|
|
+ return Py_BuildValue("s", buf);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static PyObject * wpaspy_attach(struct wpaspy_obj *self)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (self->attached)
|
|
|
+ Py_RETURN_NONE;
|
|
|
+
|
|
|
+ ret = wpa_ctrl_attach(self->ctrl);
|
|
|
+ if (ret) {
|
|
|
+ PyErr_SetString(wpaspy_error, "Attach failed");
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ Py_RETURN_NONE;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static PyObject * wpaspy_detach(struct wpaspy_obj *self)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ if (!self->attached)
|
|
|
+ Py_RETURN_NONE;
|
|
|
+
|
|
|
+ ret = wpa_ctrl_detach(self->ctrl);
|
|
|
+ if (ret) {
|
|
|
+ PyErr_SetString(wpaspy_error, "Detach failed");
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ Py_RETURN_NONE;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static PyObject * wpaspy_pending(struct wpaspy_obj *self)
|
|
|
+{
|
|
|
+ switch (wpa_ctrl_pending(self->ctrl)) {
|
|
|
+ case 1:
|
|
|
+ Py_RETURN_TRUE;
|
|
|
+ case 0:
|
|
|
+ Py_RETURN_FALSE;
|
|
|
+ default:
|
|
|
+ PyErr_SetString(wpaspy_error, "wpa_ctrl_pending failed");
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static PyObject * wpaspy_recv(struct wpaspy_obj *self)
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ char buf[4096];
|
|
|
+ size_t buflen;
|
|
|
+
|
|
|
+ buflen = sizeof(buf) - 1;
|
|
|
+ Py_BEGIN_ALLOW_THREADS
|
|
|
+ ret = wpa_ctrl_recv(self->ctrl, buf, &buflen);
|
|
|
+ Py_END_ALLOW_THREADS
|
|
|
+
|
|
|
+ if (ret) {
|
|
|
+ PyErr_SetString(wpaspy_error, "wpa_ctrl_recv failed");
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ buf[buflen] = '\0';
|
|
|
+ return Py_BuildValue("s", buf);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static PyMethodDef wpaspy_methods[] = {
|
|
|
+ {
|
|
|
+ "request", (PyCFunction) wpaspy_request, METH_VARARGS,
|
|
|
+ "Send a control interface command and return response"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "attach", (PyCFunction) wpaspy_attach, METH_NOARGS,
|
|
|
+ "Attach as an event monitor"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "detach", (PyCFunction) wpaspy_detach, METH_NOARGS,
|
|
|
+ "Detach an event monitor"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "pending", (PyCFunction) wpaspy_pending, METH_NOARGS,
|
|
|
+ "Check whether any events are pending"
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "recv", (PyCFunction) wpaspy_recv, METH_NOARGS,
|
|
|
+ "Received pending event"
|
|
|
+ },
|
|
|
+ { NULL, NULL, 0, NULL }
|
|
|
+};
|
|
|
+
|
|
|
+static PyMemberDef wpaspy_members[] = {
|
|
|
+ {
|
|
|
+ "attached", T_INT, offsetof(struct wpaspy_obj, attached),
|
|
|
+ READONLY,
|
|
|
+ "Whether instance is attached as event monitor"
|
|
|
+ },
|
|
|
+ { NULL }
|
|
|
+};
|
|
|
+
|
|
|
+static PyTypeObject wpaspy_ctrl = {
|
|
|
+ PyObject_HEAD_INIT(NULL)
|
|
|
+ .tp_name = "wpaspy.Ctrl",
|
|
|
+ .tp_basicsize = sizeof(struct wpaspy_obj),
|
|
|
+ .tp_getattro = PyObject_GenericGetAttr,
|
|
|
+ .tp_setattro = PyObject_GenericSetAttr,
|
|
|
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
|
|
+ .tp_methods = wpaspy_methods,
|
|
|
+ .tp_members = wpaspy_members,
|
|
|
+ .tp_init = (initproc) wpaspy_open,
|
|
|
+ .tp_dealloc = (destructor) wpaspy_close,
|
|
|
+ .tp_new = PyType_GenericNew,
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+static PyMethodDef module_methods[] = {
|
|
|
+ { NULL, NULL, 0, NULL }
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+PyMODINIT_FUNC initwpaspy(void)
|
|
|
+{
|
|
|
+ PyObject *mod;
|
|
|
+
|
|
|
+ PyType_Ready(&wpaspy_ctrl);
|
|
|
+ mod = Py_InitModule("wpaspy", module_methods);
|
|
|
+ wpaspy_error = PyErr_NewException("wpaspy.error", NULL, NULL);
|
|
|
+
|
|
|
+ Py_INCREF(&wpaspy_ctrl);
|
|
|
+ Py_INCREF(wpaspy_error);
|
|
|
+
|
|
|
+ PyModule_AddObject(mod, "Ctrl", (PyObject *) &wpaspy_ctrl);
|
|
|
+ PyModule_AddObject(mod, "error", wpaspy_error);
|
|
|
+}
|