1 /* ------------------------------------------------------------------------------------------------
2 jeremy@emperorlinux.com
4 This module was inspired by (and uses) the iw library that comes with the Linux Wireless Tools
5 package. The scanning portions of this module are moderately modified versions of those already
6 found in iwlist.c; however, in the future I plan to clean them up (especially the goto, wtf?)
8 Please run "pydoc pyiw" for more thorough, nicely formatted information on this module.
10 TODO: DO NOT USE DICTIONARY ACCESS! THIS IS RETARDED! :)
12 TODO: Refine WirelessInterface_Scan(). Right now there's a goto in there that makes me feel
13 pretty uncomfortable. This is probably the first thing I'll work on when I have time.
15 TODO: Add better (more robust) support for setting the various parameters on the interface.
16 The wireless world has changed a lot since I worked on this last, and there's room
17 for me to certainly clean things up.
18 ------------------------------------------------------------------------------------------------ */
21 #include <structmember.h>
24 #define PYIW_VERSION_MAJOR 0
25 #define PYIW_VERSION_MINOR 3
26 #define PYIW_VERSION_BUGFIX 3
27 #define PYIW_VERSION_STRING "0.3.3"
29 /* --------------------------------------------------------------------------- WirelessInterface */
48 } WirelessInterfaceKeyEnum;
51 WirelessInterfaceKeyEnum keys[2];
54 } WirelessInterfaceScanData;
56 static char* WirelessInterfaceKeys[] = {
69 int WirelessInterfaceNumKeys(void) {
70 return sizeof(WirelessInterfaceKeys) / sizeof(char*);
73 /* ------------------------------------------------------------------------ Function Definitions */
74 typedef struct iw_event iwevent;
75 typedef struct iwreq iwreq;
76 typedef struct ifreq ifreq;
77 typedef struct timeval timeval;
78 typedef WirelessInterface wiface;
79 typedef WirelessInterfaceScanData wifacesd;
81 static PyObject* pyiw_version (PyObject*, PyObject*);
82 static PyObject* pyiw_iw_version (PyObject*, PyObject*);
83 static PyObject* pyiw_we_version (PyObject*, PyObject*);
85 static int WirelessInterface_init (wiface*, PyObject*, PyObject*);
86 static void WirelessInterface_dealloc (wiface*);
87 static void WirelessInterface_refresh (wiface*);
88 static int WirelessInterface_len (PyObject*);
89 static PyObject* WirelessInterface_mapget (PyObject*, PyObject*);
90 static int WirelessInterface_mapset (PyObject*, PyObject*, PyObject*);
91 static PyObject* WirelessInterface_seqitem (PyObject*, int);
93 static PyObject* WirelessInterface_Scan (wiface*);
94 static int WirelessInterface_ScanItem (iwevent*, iwrange*, wifacesd*);
96 static int Py_SetValInt (PyObject*, int*, int, int);
97 static int Py_SetValDouble (PyObject*, double*, double, double);
98 static int Py_SetValString (PyObject*, char*, int);
100 static PyObject* PyIWError;
102 /* ----------------------------------------------------------------------------- PYIW_DOC_STRING */
103 static char* PYIW_DOC_STRING =
104 "PYIW defines a single class, WirelessInterface, that must be instantiated\n"
105 "with the name of the real wireless interface you wish to operate on. If\n"
106 "the interface you specify doesn't exist, or if it doesn't support wireless\n"
107 "extensions, object creation will fail and pyiw.error will be raised.. As an\n"
108 "important side note: PYIW requires at least Wireless Extensions 17. It may\n"
109 "work in other cases, depending on how much has changed in future versions.\n\n"
110 "The WirelessInterface object behaves very similarly to a dictionary and has\n"
111 "the following keys (note that values that can be reassigned are indicated\n"
112 "with the text RW); changed take effect immediately:\n\n"
113 "- essid (RW) [string]: The AP's ESSID.\n"
114 "- wep (RW) [string]: The currently used key; must be root.\n"
115 "- wpa [bool ]: Whether or not WPA was detected.\n"
116 "- mode (RW) [int ]: Auto, Ad-Hoc, Mangaged, Master,\n"
117 " Repeater, Secondary, Monitor\n"
118 "- channel (RW) [double]: US standard channels 1-12. (index 0-11)\n"
119 "- frequency [double]: The GHz freq level.\n"
120 "- protocol [string]: The name representing A, B, or G WiFi.\n"
121 "- quality [int ]: Signal quality, 1-100%.\n"
122 "- bitrate [int ]: Number of BPS; 1:1 ratio.\n"
123 "- ap_mac [string]: The address of the current AP.\n\n"
124 "--- EXAMPLE USAGE --------------------------------------\n\n"
126 " wi = pyiw.WirelessInterface(\"wlan0\")\n\n"
127 "except pyiw.error, error:\n"
131 " print param, \"-->\", wi[param]\n\n"
132 "wi[\"channel\"] = 6.0\n"
133 "wi[\"essid\" ] = \"Xenomorph\"\n"
134 "wi[\"mode\" ] = 3\n"
135 "wi[\"wep\" ] = \"AD0F44310CEF\"\n\n"
136 "nets = wi.Scan()\n\n"
138 " print net[\"essid\"]\n"
141 /* -------------------------------------------------------------------------------- Py_SetValInt */
142 static int Py_SetValInt(PyObject* arg, int* val, int min, int max) {
143 if(PyInt_Check(arg)) {
144 int tmp = (int)(PyInt_AsLong(arg));
146 if(tmp >= min && tmp <= max) {
153 PyErr_SetString(PyExc_ValueError, "Int too big/small in SetValInt");
160 PyErr_SetString(PyExc_TypeError, "Non-int argument passed to ArgToInt");
166 /* ----------------------------------------------------------------------------- Py_SetValDouble */
167 static int Py_SetValDouble(PyObject* arg, double* val, double min, double max) {
168 if(PyFloat_Check(arg)) {
169 double tmp = PyFloat_AsDouble(arg);
171 if(tmp >= min && tmp <= max) {
178 PyErr_SetString(PyExc_ValueError, "Double too big/small in SetValDouble");
185 PyErr_SetString(PyExc_TypeError, "Non-double argument passed to ArgToDouble");
191 /* ----------------------------------------------------------------------------- Py_SetValString */
192 static int Py_SetValString(PyObject* arg, char* val, int maxsize) {
193 if(PyString_Check(arg)) {
194 strncpy(val, PyString_AsString(arg), maxsize);
200 PyErr_SetString(PyExc_TypeError, "Non-string argument passed to ArgToString");
206 /* ---------------------------------------------------------------------- WirelessInterface_init */
207 static int WirelessInterface_init(wiface* self, PyObject* args, PyObject* kargs) {
209 const size_t ifnamesize;
211 memset(&(self->info), 0, sizeof(wireless_info));
216 if(PyArg_ParseTuple(args, "s#", &ifname, &ifnamesize)) {
217 self->sock = iw_sockets_open();
219 if(self->sock != -1) {
222 self->ifname = malloc(ifnamesize + 1);
224 strncpy(self->ifname, ifname, ifnamesize + 1);
225 strncpy(frq.ifr_name, self->ifname, IFNAMSIZ);
227 if(!ioctl(self->sock, SIOCGIFFLAGS, &frq)) {
228 frq.ifr_flags |= IFF_UP | IFF_RUNNING;
230 ioctl(self->sock, SIOCSIFFLAGS, &frq);
232 WirelessInterface_refresh(self);
237 else PyErr_SetString(PyIWError, "Failed to find device");
240 else PyErr_SetString(PyIWError, "Failed to connect to libiw");
246 /* ------------------------------------------------------------------- WirelessInterface_dealloc */
247 static void WirelessInterface_dealloc(wiface* self) {
248 if(self->ifname) free(self->ifname);
250 iw_sockets_close(self->sock);
251 self->ob_type->tp_free((PyObject*)(self));
254 /* ------------------------------------------------------------------- WirelessInterface_refresh */
255 static void WirelessInterface_refresh(wiface* self) {
258 iw_get_basic_config(self->sock, self->ifname, &(self->info.b));
259 iw_get_range_info(self->sock, self->ifname, &(self->info.range));
261 iw_get_ext(self->sock, self->ifname, SIOCGIWRATE, &wrq);
262 memcpy(&(self->info.bitrate), &wrq.u.bitrate, sizeof(iwparam));
264 iw_get_ext(self->sock, self->ifname, SIOCGIWAP, &wrq);
265 memcpy(&(self->info.ap_addr), &wrq.u.ap_addr, sizeof (sockaddr));
268 self->sock, self->ifname, &(self->info.stats),
269 &(self->info.range), self->info.has_range
273 /* ----------------------------------------------------------------------- WirelessInterface_len */
274 static int WirelessInterface_len(PyObject* self) {
275 return WirelessInterfaceNumKeys();
278 /* -------------------------------------------------------------------- WirelessInterface_mapget */
279 static PyObject* WirelessInterface_mapget(PyObject* self, PyObject* arg) {
280 if(PyString_Check(arg)) {
281 wiface* wi = (wiface*)(self);
282 char* key = PyString_AsString(arg);
284 static char buf[128];
286 WirelessInterface_refresh(wi);
289 if(!strncmp(key, "essid", 5)) return Py_BuildValue(
290 "s", wi->info.b.essid
294 else if(!strncmp(key, "wep", 3)) {
297 sizeof(buf) / sizeof(char),
303 if(!strncmp(buf, "00", 2)) return Py_BuildValue("s", "MUST_BE_ROOT");
304 else return Py_BuildValue("s", buf);
308 else if(!strncmp(key, "wpa", 3)) return Py_BuildValue(
309 "s", "Unsupported in pyiw version " PYIW_VERSION_STRING
313 else if(!strncmp(key, "protocol", 8)) return Py_BuildValue(
318 else if(!strncmp(key, "frequency", 9)) {
319 double freq = wi->info.b.freq;
321 if(freq <= 14.0) iw_channel_to_freq((int)(freq), &freq, &(wi->info.range));
323 return Py_BuildValue("d", freq);
327 else if(!strncmp(key, "channel", 7)) {
328 double freq = wi->info.b.freq;
331 freq = (double)(iw_freq_to_channel(freq, &(wi->info.range)));
334 return Py_BuildValue("d", freq);
338 else if(!strncmp(key, "mode", 7)) return Py_BuildValue(
339 "s", iw_operation_mode[wi->info.b.mode]
343 else if(!strncmp(key, "bitrate", 7)) return Py_BuildValue(
344 "i", wi->info.bitrate.value
348 else if(!strncmp(key, "quality", 7)) return Py_BuildValue(
349 "i", wi->info.stats.qual.qual
353 else if(!strncmp(key, "ap_mac", 6)) {
354 /* iw_pr_ether(buf, wi->info.ap_addr.sa_data); */
355 /* iw_ether_ntop((const struct ether_addr *) addr, bufp); */
357 (const struct ether_addr*)(wi->info.ap_addr.sa_data),
361 return Py_BuildValue("s", buf);
365 PyErr_SetString(PyExc_ValueError, "Bad key in WirelessInterface_mapget");
371 PyErr_SetString(PyExc_TypeError, "Bad key type in WirelessInterface_mapget");
375 /* -------------------------------------------------------------------- WirelessInterface_mapset */
376 static int WirelessInterface_mapset(PyObject* self, PyObject* arg, PyObject* val) {
377 if(PyString_Check(arg)) {
378 wiface* wi = (wiface*)(self);
379 char* key = PyString_AsString(arg);
383 memset(&wreq, 0, sizeof(struct iwreq));
386 if(!strncmp(key, "essid", 5)) {
387 if(!Py_SetValString(val, wi->info.b.essid, sizeof(wi->info.b.essid))) {
388 wreq.u.essid.flags = 1;
389 wreq.u.essid.pointer = wi->info.b.essid;
390 wreq.u.essid.length = strlen(wi->info.b.essid) + 1;
393 printf("PYIW DEBUG: iw_set_ext (ESSID) with %s\n", wi->info.b.essid);
396 ret = iw_set_ext(wi->sock, wi->ifname, SIOCSIWESSID, &wreq);
399 printf("PYIW DEBUG: iw_set_ext (ESSID) returned %d\n", ret);
409 else if(!strncmp(key, "wep", 3)) {
410 if(PyString_Check(arg)) {
413 memset(wi->info.b.key, 0, IW_ENCODING_TOKEN_MAX);
416 PyString_AsString(val), wi->info.b.key
419 wreq.u.data.length = len;
420 wreq.u.data.pointer = wi->info.b.key;
422 ret = iw_set_ext(wi->sock, wi->ifname, SIOCSIWENCODE, &wreq);
424 wi->info.b.has_key = 1;
425 wi->info.b.key_size = len;
428 printf("PYIW DEBUG: iw_in_key returned: %d\n", len);
429 printf("PYIW DEBUG: iw_set_ext (ENCODE) returned: %d\n", ret);
436 PyErr_SetString(PyExc_TypeError, "Key must be a string");
442 else if(!strncmp(key, "channel", 7)) {
443 if(!Py_SetValDouble(val, &(wi->info.b.freq), 1.0, 12.0)) {
444 iw_float2freq(wi->info.b.freq, &(wreq.u.freq));
446 if(iw_set_ext(wi->sock, wi->ifname, SIOCSIWFREQ, &wreq)) return -1;
455 else if(!strncmp(key, "mode", 4)) return Py_SetValInt(
456 val, &(wi->info.b.mode), 0, 6
460 PyErr_SetString(PyExc_ValueError, "Bad key in WirelessInterface_mapset");
466 PyErr_SetString(PyExc_TypeError, "Bad key type in WirelessInterface_mapset");
471 /* ------------------------------------------------------------------- WirelessInterface_seqitem */
472 static PyObject* WirelessInterface_seqitem(PyObject* self, int index) {
473 if(index >= 0 && index < WirelessInterfaceNumKeys()) return Py_BuildValue(
474 "s", WirelessInterfaceKeys[index]
480 /* ---------------------------------------------------------------------- WirelessInterface_Scan */
481 static PyObject* WirelessInterface_Scan(wiface* self) {
483 unsigned char* buffer = NULL;
484 int buflen = IW_SCAN_MAX_DATA;
488 int timeout = 10000000;
489 PyObject* scan_list = NULL;
491 has_range = (iw_get_range_info(self->sock, self->ifname, &range) >= 0);
495 wrq.u.data.pointer = NULL;
496 wrq.u.data.flags = 0;
497 wrq.u.data.length = 0;
499 if(iw_set_ext(self->sock, self->ifname, SIOCSIWSCAN, &wrq) < 0) {
501 PyErr_SetString(PyIWError, "Interface doesn't support scanning");
509 timeout -= tv.tv_usec;
519 ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
522 if(errno == EAGAIN || errno == EINTR) continue;
525 PyErr_SetString(PyIWError, "Unknown scanning error");
532 unsigned char* newbuf;
535 newbuf = realloc(buffer, buflen);
538 if(buffer) free(buffer);
540 PyErr_SetString(PyIWError, "Memory allocation failure in scan");
547 wrq.u.data.pointer = buffer;
548 wrq.u.data.flags = 0;
549 wrq.u.data.length = buflen;
551 if(iw_get_ext(self->sock, self->ifname, SIOCGIWSCAN, &wrq) < 0) {
552 if((errno == E2BIG)) {
553 if(wrq.u.data.length > buflen) buflen = wrq.u.data.length;
559 if(errno == EAGAIN) {
562 timeout -= tv.tv_usec;
564 if(timeout > 0) continue;
569 PyErr_SetString(PyIWError, "Unable to read scan data");
578 if(wrq.u.data.length) {
582 PyObject* scan_dict = NULL;
584 scan_list = PyList_New(0);
586 iw_init_event_stream(&stream, (char*)(buffer), wrq.u.data.length);
589 ret = iw_extract_event_stream(&stream, &iwe, range.we_version_compiled);
593 int sr = WirelessInterface_ScanItem(&iwe, &range, &sd);
599 PyList_Append(scan_list, scan_dict);
600 Py_DECREF(scan_dict);
603 scan_dict = PyDict_New();
605 for(i = 0; i < WirelessInterfaceNumKeys(); i++) {
606 PyMapping_SetItemString(
608 WirelessInterfaceKeys[i],
617 for(i = 0; i < sd.num; i++) {
618 PyMapping_SetItemString(
620 WirelessInterfaceKeys[sd.keys[i]],
624 Py_DECREF(sd.objs[i]);
632 PyList_Append(scan_list, scan_dict);
633 Py_XDECREF(scan_dict);
636 else return Py_BuildValue("[]");
643 /* ------------------------------------------------------------------ WirelessInterface_ScanItem */
644 static int WirelessInterface_ScanItem(iwevent* event, iwrange* range, wifacesd* data) {
645 static char buf[128];
647 memset(data, 0, sizeof(wifacesd));
652 (const struct ether_addr*)(event->u.ap_addr.sa_data),
656 data->keys[0] = PYIW_KE_AP_MAC;
657 data->objs[0] = Py_BuildValue("s", buf);
664 double freq = iw_freq2float(&(event->u.freq));
667 if(freq <= 14.0) channel = iw_channel_to_freq((int)(freq), &freq, range);
668 else channel = iw_freq_to_channel(freq, range);
670 data->keys[0] = PYIW_KE_FREQUENCY;
671 data->keys[1] = PYIW_KE_CHANNEL;
672 data->objs[0] = Py_BuildValue("d", freq);
673 data->objs[1] = Py_BuildValue("i", channel);
680 data->keys[0] = PYIW_KE_MODE;
681 data->objs[0] = Py_BuildValue("s", iw_operation_mode[event->u.mode]);
688 data->keys[0] = PYIW_KE_PROTOCOL;
689 data->objs[0] = Py_BuildValue("s", event->u.name);
696 memcpy(buf, event->u.essid.pointer, event->u.essid.length);
697 buf[event->u.essid.length] = 0x0;
699 data->keys[0] = PYIW_KE_ESSID;
700 data->objs[0] = Py_BuildValue("s", buf);
706 case SIOCGIWENCODE: {
709 if(event->u.data.flags & IW_ENCODE_DISABLED) pybool = Py_False;
710 else pybool = Py_True;
714 data->keys[0] = PYIW_KE_WEP;
715 data->objs[0] = pybool;
722 data->keys[0] = PYIW_KE_BITRATE;
723 data->objs[0] = Py_BuildValue("i", event->u.bitrate.value);
730 data->keys[0] = PYIW_KE_QUALITY;
731 data->objs[0] = Py_BuildValue("i", event->u.qual.qual);
738 PyObject* pytrue = Py_True;
741 data->keys[0] = PYIW_KE_WPA;
742 data->objs[0] = pytrue;
749 memcpy(buf, event->u.data.pointer, event->u.data.length);
750 buf[event->u.data.length] = 0x0;
752 if(strstr(buf, "wpa_ie")) {
753 PyObject* pytrue = Py_True;
756 data->keys[0] = PYIW_KE_WPA;
757 data->objs[0] = pytrue;
761 memset(buf, 0, sizeof(buf));
768 /* -------------------------------------------------------------------- Member/Method Structures */
769 static PyMethodDef module_methods[] = {
771 "version", pyiw_version, METH_NOARGS,
772 "Returns the current PyIW version."
775 "iw_version", pyiw_iw_version, METH_NOARGS,
776 "Returns the current Wireless Extnesions (libiw WE) version."
779 "we_version", pyiw_we_version, METH_NOARGS,
780 "Returns the current Wireless Extensions (kernel-level WE) version."
782 { NULL, NULL, 0, NULL }
785 static PyMethodDef WirelessInterface_methods[] = {
787 "Scan", (PyCFunction)(WirelessInterface_Scan), METH_NOARGS,
788 "This function will attempt to scan any local AP's and return a tuple\n"
789 "of objectes representing the data contained therein."
791 { NULL, NULL, 0, NULL }
794 static PyMappingMethods WirelessInterface_mapping_methods = {
795 WirelessInterface_len, /* length */
796 WirelessInterface_mapget, /* getitem */
797 WirelessInterface_mapset /* setitem */
800 static PySequenceMethods WirelessInterface_sequence_methods = {
801 WirelessInterface_len, /* sq_length */
804 WirelessInterface_seqitem, /* sq_item */
807 0, /* sq_ass_slice */
809 0, /* sq_inplace_concat */
810 0 /* sq_inplace_repeat */
813 /* -------------------------------------------------------------------- PyType_WirelessInterface */
814 static PyTypeObject PyType_WirelessInterface = {
815 PyObject_HEAD_INIT(NULL)
817 "pyiw.WirelessInterface", /* tp_name */
818 sizeof(WirelessInterface), /* tp_basicsize */
820 (destructor)(WirelessInterface_dealloc), /* tp_dealloc */
826 0, /* tp_as_number */
827 &WirelessInterface_sequence_methods, /* tp_as_sequence */
828 &WirelessInterface_mapping_methods, /* tp_as_mapping */
834 0, /* tp_as_buffer */
835 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
839 0, /* tp_richcompare */
840 0, /* tp_weaklistoffset */
843 WirelessInterface_methods, /* tp_methods */
848 0, /* tp_descr_get */
849 0, /* tp_descr_set */
850 0, /* tp_dictoffset */
851 (initproc)(WirelessInterface_init), /* tp_init */
853 PyType_GenericNew, /* tp_new */
859 0, /* tp_subclasses */
864 /* ------------------------------------------------------------------------------------ initpyiw */
865 PyMODINIT_FUNC initpyiw(void) {
868 PyType_Ready(&PyType_WirelessInterface);
870 module = Py_InitModule3("pyiw", module_methods, PYIW_DOC_STRING);
871 PyIWError = PyErr_NewException("pyiw.error", NULL, NULL);
873 Py_INCREF(&PyType_WirelessInterface);
874 Py_INCREF(PyIWError);
876 PyModule_AddObject(module, "WirelessInterface", (PyObject*)(&PyType_WirelessInterface));
877 PyModule_AddObject(module, "error", PyIWError);
880 static PyObject* pyiw_version(PyObject* u1, PyObject* u2) {
881 return Py_BuildValue("(iii)",
888 static PyObject* pyiw_iw_version(PyObject* u1, PyObject* u2) {
889 return Py_BuildValue("i", WE_VERSION);
892 static PyObject* pyiw_we_version(PyObject* u1, PyObject* u2) {
893 return Py_BuildValue("i", iw_get_kernel_we_version());