1 /*
2 * Python bindings for wpa_ctrl (wpa_supplicant/hostapd control interface)
3 * Copyright (c) 2013, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include <Python.h>
10 #include <structmember.h>
11
12 #include "wpa_ctrl.h"
13
14
15 struct wpaspy_obj {
16 PyObject_HEAD
17 struct wpa_ctrl *ctrl;
18 int attached;
19 };
20
21 static PyObject *wpaspy_error;
22
23
wpaspy_open(struct wpaspy_obj * self,PyObject * args)24 static int wpaspy_open(struct wpaspy_obj *self, PyObject *args)
25 {
26 const char *path;
27
28 if (!PyArg_ParseTuple(args, "s", &path))
29 return -1;
30 self->ctrl = wpa_ctrl_open(path);
31 if (self->ctrl == NULL)
32 return -1;
33 self->attached = 0;
34 return 0;
35 }
36
37
wpaspy_close(struct wpaspy_obj * self)38 static void wpaspy_close(struct wpaspy_obj *self)
39 {
40 if (self->ctrl) {
41 if (self->attached)
42 wpa_ctrl_detach(self->ctrl);
43 wpa_ctrl_close(self->ctrl);
44 self->ctrl = NULL;
45 }
46
47 PyObject_Del(self);
48 }
49
50
wpaspy_request(struct wpaspy_obj * self,PyObject * args)51 static PyObject * wpaspy_request(struct wpaspy_obj *self, PyObject *args)
52 {
53 const char *cmd;
54 char buf[4096];
55 size_t buflen;
56 int ret;
57
58 if (!PyArg_ParseTuple(args, "s", &cmd))
59 return NULL;
60
61 buflen = sizeof(buf) - 1;
62 ret = wpa_ctrl_request(self->ctrl, cmd, strlen(cmd), buf, &buflen,
63 NULL);
64 if (ret == -2) {
65 PyErr_SetString(wpaspy_error, "Request timed out");
66 return NULL;
67 }
68 if (ret) {
69 PyErr_SetString(wpaspy_error, "Request failed");
70 return NULL;
71 }
72
73 buf[buflen] = '\0';
74 return Py_BuildValue("s", buf);
75 }
76
77
wpaspy_attach(struct wpaspy_obj * self)78 static PyObject * wpaspy_attach(struct wpaspy_obj *self)
79 {
80 int ret;
81
82 if (self->attached)
83 Py_RETURN_NONE;
84
85 ret = wpa_ctrl_attach(self->ctrl);
86 if (ret) {
87 PyErr_SetString(wpaspy_error, "Attach failed");
88 return NULL;
89 }
90 Py_RETURN_NONE;
91 }
92
93
wpaspy_detach(struct wpaspy_obj * self)94 static PyObject * wpaspy_detach(struct wpaspy_obj *self)
95 {
96 int ret;
97
98 if (!self->attached)
99 Py_RETURN_NONE;
100
101 ret = wpa_ctrl_detach(self->ctrl);
102 if (ret) {
103 PyErr_SetString(wpaspy_error, "Detach failed");
104 return NULL;
105 }
106 Py_RETURN_NONE;
107 }
108
109
wpaspy_pending(struct wpaspy_obj * self)110 static PyObject * wpaspy_pending(struct wpaspy_obj *self)
111 {
112 switch (wpa_ctrl_pending(self->ctrl)) {
113 case 1:
114 Py_RETURN_TRUE;
115 case 0:
116 Py_RETURN_FALSE;
117 default:
118 PyErr_SetString(wpaspy_error, "wpa_ctrl_pending failed");
119 break;
120 }
121
122 return NULL;
123 }
124
125
wpaspy_recv(struct wpaspy_obj * self)126 static PyObject * wpaspy_recv(struct wpaspy_obj *self)
127 {
128 int ret;
129 char buf[4096];
130 size_t buflen;
131
132 buflen = sizeof(buf) - 1;
133 Py_BEGIN_ALLOW_THREADS
134 ret = wpa_ctrl_recv(self->ctrl, buf, &buflen);
135 Py_END_ALLOW_THREADS
136
137 if (ret) {
138 PyErr_SetString(wpaspy_error, "wpa_ctrl_recv failed");
139 return NULL;
140 }
141
142 buf[buflen] = '\0';
143 return Py_BuildValue("s", buf);
144 }
145
146
147 static PyMethodDef wpaspy_methods[] = {
148 {
149 "request", (PyCFunction) wpaspy_request, METH_VARARGS,
150 "Send a control interface command and return response"
151 },
152 {
153 "attach", (PyCFunction) wpaspy_attach, METH_NOARGS,
154 "Attach as an event monitor"
155 },
156 {
157 "detach", (PyCFunction) wpaspy_detach, METH_NOARGS,
158 "Detach an event monitor"
159 },
160 {
161 "pending", (PyCFunction) wpaspy_pending, METH_NOARGS,
162 "Check whether any events are pending"
163 },
164 {
165 "recv", (PyCFunction) wpaspy_recv, METH_NOARGS,
166 "Received pending event"
167 },
168 { NULL, NULL, 0, NULL }
169 };
170
171 static PyMemberDef wpaspy_members[] = {
172 {
173 "attached", T_INT, offsetof(struct wpaspy_obj, attached),
174 READONLY,
175 "Whether instance is attached as event monitor"
176 },
177 { NULL }
178 };
179
180 static PyTypeObject wpaspy_ctrl = {
181 PyObject_HEAD_INIT(NULL)
182 .tp_name = "wpaspy.Ctrl",
183 .tp_basicsize = sizeof(struct wpaspy_obj),
184 .tp_getattro = PyObject_GenericGetAttr,
185 .tp_setattro = PyObject_GenericSetAttr,
186 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
187 .tp_methods = wpaspy_methods,
188 .tp_members = wpaspy_members,
189 .tp_init = (initproc) wpaspy_open,
190 .tp_dealloc = (destructor) wpaspy_close,
191 .tp_new = PyType_GenericNew,
192 };
193
194
195 #if PY_MAJOR_VERSION < 3
196 static PyMethodDef module_methods[] = {
197 { NULL, NULL, 0, NULL }
198 };
199
200
initwpaspy(void)201 PyMODINIT_FUNC initwpaspy(void)
202 {
203 PyObject *mod;
204
205 PyType_Ready(&wpaspy_ctrl);
206 mod = Py_InitModule("wpaspy", module_methods);
207 wpaspy_error = PyErr_NewException("wpaspy.error", NULL, NULL);
208
209 Py_INCREF(&wpaspy_ctrl);
210 Py_INCREF(wpaspy_error);
211
212 PyModule_AddObject(mod, "Ctrl", (PyObject *) &wpaspy_ctrl);
213 PyModule_AddObject(mod, "error", wpaspy_error);
214 }
215 #else
216 static struct PyModuleDef wpaspy_def = {
217 PyModuleDef_HEAD_INIT,
218 "wpaspy",
219 };
220
221
initwpaspy(void)222 PyMODINIT_FUNC initwpaspy(void)
223 {
224 PyObject *mod;
225
226 mod = PyModule_Create(&wpaspy_def);
227 if (!mod)
228 return NULL;
229
230 wpaspy_error = PyErr_NewException("wpaspy.error", NULL, NULL);
231
232 Py_INCREF(&wpaspy_ctrl);
233 Py_INCREF(wpaspy_error);
234
235 if (PyModule_AddObject(mod, "Ctrl", (PyObject *) &wpaspy_ctrl) < 0 ||
236 PyModule_AddObject(mod, "error", wpaspy_error) < 0) {
237 Py_DECREF(&wpaspy_ctrl);
238 Py_DECREF(wpaspy_error);
239 Py_DECREF(mod);
240 mod = NULL;
241 }
242
243 return mod;
244 }
245 #endif
246