wpaspy: Add Python bindings for wpa_ctrl
This allows Python to be used to control wpa_supplicant/hostapd through the control interface. Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
77e4e85321
commit
20da5c8986
4 changed files with 320 additions and 0 deletions
14
wpaspy/Makefile
Normal file
14
wpaspy/Makefile
Normal file
|
@ -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
|
22
wpaspy/setup.py
Normal file
22
wpaspy/setup.py
Normal file
|
@ -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)')
|
70
wpaspy/test.py
Executable file
70
wpaspy/test.py
Executable file
|
@ -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()
|
214
wpaspy/wpaspy.c
Normal file
214
wpaspy/wpaspy.c
Normal file
|
@ -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);
|
||||
}
|
Loading…
Reference in a new issue