aboutsummaryrefslogtreecommitdiffstats
path: root/wpaspy
diff options
context:
space:
mode:
Diffstat (limited to 'wpaspy')
-rw-r--r--wpaspy/Makefile14
-rw-r--r--wpaspy/setup.py22
-rwxr-xr-xwpaspy/test.py70
-rw-r--r--wpaspy/wpaspy.c214
4 files changed, 320 insertions, 0 deletions
diff --git a/wpaspy/Makefile b/wpaspy/Makefile
new file mode 100644
index 0000000..bc920e0
--- /dev/null
+++ b/wpaspy/Makefile
@@ -0,0 +1,14 @@
+all: build
+
+SRC=wpaspy.c
+
+build: $(SRC) setup.py
+ python setup.py build
+
+install:
+ python setup.py install
+
+clean:
+ python setup.py clean
+ rm -f *~
+ rm -rf build
diff --git a/wpaspy/setup.py b/wpaspy/setup.py
new file mode 100644
index 0000000..4dbf765
--- /dev/null
+++ b/wpaspy/setup.py
@@ -0,0 +1,22 @@
+#!/usr/bin/python
+#
+# 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.
+
+from distutils.core import setup, Extension
+
+ext = Extension(name = 'wpaspy',
+ sources = ['../src/common/wpa_ctrl.c',
+ '../src/utils/os_unix.c',
+ 'wpaspy.c'],
+ extra_compile_args = ["-I../src/common",
+ "-I../src/utils",
+ "-DCONFIG_CTRL_IFACE",
+ "-DCONFIG_CTRL_IFACE_UNIX"])
+
+setup(name = 'wpaspy',
+ ext_modules = [ext],
+ description = 'Python bindings for wpa_ctrl (wpa_supplicant/hostapd)')
diff --git a/wpaspy/test.py b/wpaspy/test.py
new file mode 100755
index 0000000..2a5e409
--- /dev/null
+++ b/wpaspy/test.py
@@ -0,0 +1,70 @@
+#!/usr/bin/python
+#
+# Test script for wpaspy
+# 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.
+
+import os
+import time
+import wpaspy
+
+wpas_ctrl = '/var/run/wpa_supplicant'
+
+def wpas_connect():
+ ifaces = []
+ if os.path.isdir(wpas_ctrl):
+ try:
+ ifaces = [os.path.join(wpas_ctrl, i) for i in os.listdir(wpas_ctrl)]
+ except OSError, error:
+ print "Could not find wpa_supplicant: ", error
+ return None
+
+ if len(ifaces) < 1:
+ print "No wpa_supplicant control interface found"
+ return None
+
+ for ctrl in ifaces:
+ try:
+ wpas = wpaspy.Ctrl(ctrl)
+ return wpas
+ except wpactrl.error, error:
+ print "Error: ", error
+ pass
+ return None
+
+
+def main():
+ print "Testing wpa_supplicant control interface connection"
+ wpas = wpas_connect()
+ if wpas is None:
+ return
+ print "Connected to wpa_supplicant"
+ print wpas.request('PING')
+
+ mon = wpas_connect()
+ if mon is None:
+ print "Could not open event monitor connection"
+ return
+
+ mon.attach()
+ print "Scan"
+ print wpas.request('SCAN')
+
+ count = 0
+ while count < 10:
+ count += 1
+ time.sleep(1)
+ while mon.pending():
+ ev = mon.recv()
+ print ev
+ if 'CTRL-EVENT-SCAN-RESULTS' in ev:
+ print 'Scan completed'
+ print wpas.request('SCAN_RESULTS')
+ count = 10
+ pass
+
+
+if __name__ == "__main__":
+ main()
diff --git a/wpaspy/wpaspy.c b/wpaspy/wpaspy.c
new file mode 100644
index 0000000..278089b
--- /dev/null
+++ b/wpaspy/wpaspy.c
@@ -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);
+}