 20da5c8986
			
		
	
	
		20da5c8986
		
	
	
	
	
		
			
			This allows Python to be used to control wpa_supplicant/hostapd through the control interface. Signed-hostap: Jouni Malinen <j@w1.fi>
		
			
				
	
	
		
			214 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * 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);
 | |
| }
 |