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 */
51 } WirelessInterfaceKeyEnum;
54 WirelessInterfaceKeyEnum keys[3];
57 } WirelessInterfaceScanData;
59 static char* WirelessInterfaceKeys[] = {
75 int WirelessInterfaceNumKeys(void) {
76 return sizeof(WirelessInterfaceKeys) / sizeof(char*);
79 /* ------------------------------------------------------------------------ Function Definitions */
80 typedef struct iw_event iwevent;
81 typedef struct iwreq iwreq;
82 typedef struct ifreq ifreq;
83 typedef struct timeval timeval;
84 typedef WirelessInterface wiface;
85 typedef WirelessInterfaceScanData wifacesd;
87 static PyObject* pyiw_version (PyObject*, PyObject*);
88 static PyObject* pyiw_iw_version (PyObject*, PyObject*);
89 static PyObject* pyiw_we_version (PyObject*, PyObject*);
91 static int WirelessInterface_init (wiface*, PyObject*, PyObject*);
92 static void WirelessInterface_dealloc (wiface*);
93 static void WirelessInterface_refresh (wiface*);
94 static int WirelessInterface_len (PyObject*);
95 static PyObject* WirelessInterface_mapget (PyObject*, PyObject*);
96 static int WirelessInterface_mapset (PyObject*, PyObject*, PyObject*);
97 static PyObject* WirelessInterface_seqitem (PyObject*, int);
99 static PyObject* WirelessInterface_Scan (wiface*);
100 static int WirelessInterface_ScanItem (iwevent*, iwrange*, wifacesd*);
102 static int Py_SetValInt (PyObject*, int*, int, int);
103 static int Py_SetValDouble (PyObject*, double*, double, double);
104 static int Py_SetValString (PyObject*, char*, int);
106 static PyObject* PyIWError;
108 /* ----------------------------------------------------------------------------- PYIW_DOC_STRING */
109 static char* PYIW_DOC_STRING =
110 "PYIW defines a single class, WirelessInterface, that must be instantiated\n"
111 "with the name of the real wireless interface you wish to operate on. If\n"
112 "the interface you specify doesn't exist, or if it doesn't support wireless\n"
113 "extensions, object creation will fail and pyiw.error will be raised.. As an\n"
114 "important side note: PYIW requires at least Wireless Extensions 17. It may\n"
115 "work in other cases, depending on how much has changed in future versions.\n\n"
116 "The WirelessInterface object behaves very similarly to a dictionary and has\n"
117 "the following keys (note that values that can be reassigned are indicated\n"
118 "with the text RW); changed take effect immediately:\n\n"
119 "- essid (RW) [string]: The AP's ESSID.\n"
120 "- wep (RW) [string]: The currently used key; must be root.\n"
121 "- wpa [bool ]: Whether or not WPA was detected.\n"
122 "- mode (RW) [int ]: Auto, Ad-Hoc, Mangaged, Master,\n"
123 " Repeater, Secondary, Monitor\n"
124 "- channel (RW) [double]: US standard channels 1-12. (index 0-11)\n"
125 "- frequency [double]: The GHz freq level.\n"
126 "- protocol [string]: The name representing A, B, or G WiFi.\n"
127 "- quality [int ]: Signal quality, 1-100%.\n"
128 "- level [int ]: Signal level (dBm).\n"
129 "- noise [int ]: Noise level (dBm).\n"
130 "- txpower [int ]: Transmit power (dBm).\n"
131 "- bitrate [int ]: Number of BPS; 1:1 ratio.\n"
132 "- ap_mac [string]: The address of the current AP.\n\n"
133 "--- EXAMPLE USAGE --------------------------------------\n\n"
135 " wi = pyiw.WirelessInterface(\"wlan0\")\n\n"
136 "except pyiw.error, error:\n"
140 " print param, \"-->\", wi[param]\n\n"
141 "wi[\"channel\"] = 6.0\n"
142 "wi[\"essid\" ] = \"Xenomorph\"\n"
143 "wi[\"mode\" ] = 3\n"
144 "wi[\"wep\" ] = \"AD0F44310CEF\"\n\n"
145 "nets = wi.Scan()\n\n"
147 " print net[\"essid\"]\n"
150 /* -------------------------------------------------------------------------------- Py_SetValInt */
151 static int Py_SetValInt(PyObject* arg, int* val, int min, int max) {
152 if(PyInt_Check(arg)) {
153 int tmp = (int)(PyInt_AsLong(arg));
155 if(tmp >= min && tmp <= max) {
162 PyErr_SetString(PyExc_ValueError, "Int too big/small in SetValInt");
169 PyErr_SetString(PyExc_TypeError, "Non-int argument passed to ArgToInt");
175 /* ----------------------------------------------------------------------------- Py_SetValDouble */
176 static int Py_SetValDouble(PyObject* arg, double* val, double min, double max) {
177 if(PyFloat_Check(arg)) {
178 double tmp = PyFloat_AsDouble(arg);
180 if(tmp >= min && tmp <= max) {
187 PyErr_SetString(PyExc_ValueError, "Double too big/small in SetValDouble");
194 PyErr_SetString(PyExc_TypeError, "Non-double argument passed to ArgToDouble");
200 /* ----------------------------------------------------------------------------- Py_SetValString */
201 static int Py_SetValString(PyObject* arg, char* val, int maxsize) {
202 if(PyString_Check(arg)) {
203 strncpy(val, PyString_AsString(arg), maxsize);
209 PyErr_SetString(PyExc_TypeError, "Non-string argument passed to ArgToString");
215 /* ---------------------------------------------------------------------- WirelessInterface_init */
216 static int WirelessInterface_init(wiface* self, PyObject* args, PyObject* kargs) {
218 const size_t ifnamesize;
220 memset(&(self->info), 0, sizeof(wireless_info));
225 if(PyArg_ParseTuple(args, "s#", &ifname, &ifnamesize)) {
226 self->sock = iw_sockets_open();
228 if(self->sock != -1) {
231 self->ifname = malloc(ifnamesize + 1);
233 strncpy(self->ifname, ifname, ifnamesize + 1);
234 strncpy(frq.ifr_name, self->ifname, IFNAMSIZ);
236 if(!ioctl(self->sock, SIOCGIFFLAGS, &frq)) {
237 frq.ifr_flags |= IFF_UP | IFF_RUNNING;
239 ioctl(self->sock, SIOCSIFFLAGS, &frq);
241 WirelessInterface_refresh(self);
246 else PyErr_SetString(PyIWError, "Failed to find device");
249 else PyErr_SetString(PyIWError, "Failed to connect to libiw");
255 /* ------------------------------------------------------------------- WirelessInterface_dealloc */
256 static void WirelessInterface_dealloc(wiface* self) {
257 if(self->ifname) free(self->ifname);
259 iw_sockets_close(self->sock);
260 self->ob_type->tp_free((PyObject*)(self));
263 /* ------------------------------------------------------------------- WirelessInterface_refresh */
264 static void WirelessInterface_refresh(wiface* self) {
267 iw_get_basic_config(self->sock, self->ifname, &(self->info.b));
268 iw_get_range_info(self->sock, self->ifname, &(self->info.range));
270 iw_get_ext(self->sock, self->ifname, SIOCGIWRATE, &wrq);
271 memcpy(&(self->info.bitrate), &wrq.u.bitrate, sizeof(iwparam));
273 iw_get_ext(self->sock, self->ifname, SIOCGIWAP, &wrq);
274 memcpy(&(self->info.ap_addr), &wrq.u.ap_addr, sizeof (sockaddr));
277 self->sock, self->ifname, &(self->info.stats),
278 &(self->info.range), self->info.has_range
282 /* ----------------------------------------------------------------------- WirelessInterface_len */
283 static int WirelessInterface_len(PyObject* self) {
284 return WirelessInterfaceNumKeys();
287 /* -------------------------------------------------------------------- WirelessInterface_mapget */
288 static PyObject* WirelessInterface_mapget(PyObject* self, PyObject* arg) {
289 if(PyString_Check(arg)) {
290 wiface* wi = (wiface*)(self);
291 char* key = PyString_AsString(arg);
293 static char buf[128];
295 WirelessInterface_refresh(wi);
298 if(!strncmp(key, "essid", 5)) return Py_BuildValue(
299 "s", wi->info.b.essid
303 else if(!strncmp(key, "wep", 3)) {
306 sizeof(buf) / sizeof(char),
312 if(!strncmp(buf, "00", 2)) return Py_BuildValue("s", "MUST_BE_ROOT");
313 else return Py_BuildValue("s", buf);
317 else if(!strncmp(key, "wpa", 3)) return Py_BuildValue(
318 "s", "Unsupported in pyiw version " PYIW_VERSION_STRING
322 else if(!strncmp(key, "protocol", 8)) return Py_BuildValue(
327 else if(!strncmp(key, "frequency", 9)) {
328 double freq = wi->info.b.freq;
330 if(freq <= 14.0) iw_channel_to_freq((int)(freq), &freq, &(wi->info.range));
332 return Py_BuildValue("d", freq);
336 else if(!strncmp(key, "channel", 7)) {
337 double freq = wi->info.b.freq;
340 freq = (double)(iw_freq_to_channel(freq, &(wi->info.range)));
343 return Py_BuildValue("d", freq);
347 else if(!strncmp(key, "mode", 7)) return Py_BuildValue(
348 "s", iw_operation_mode[wi->info.b.mode]
352 else if(!strncmp(key, "bitrate", 7)) return Py_BuildValue(
353 "i", wi->info.bitrate.value
357 else if(!strncmp(key, "txpower", 7)) return Py_BuildValue(
358 "i", wi->info.txpower.value
362 else if(!strncmp(key, "quality", 7)) return Py_BuildValue(
363 "i", wi->info.stats.qual.qual
367 else if(!strncmp(key, "level", 5)) return Py_BuildValue(
368 "i", wi->info.stats.qual.level - 0x100
372 else if(!strncmp(key, "noise", 5)) return Py_BuildValue(
373 "i", wi->info.stats.qual.noise - 0x100
377 else if(!strncmp(key, "ap_mac", 6)) {
378 /* iw_pr_ether(buf, wi->info.ap_addr.sa_data); */
379 /* iw_ether_ntop((const struct ether_addr *) addr, bufp); */
381 (const struct ether_addr*)(wi->info.ap_addr.sa_data),
385 return Py_BuildValue("s", buf);
389 PyErr_SetString(PyExc_ValueError, "Bad key in WirelessInterface_mapget");
395 PyErr_SetString(PyExc_TypeError, "Bad key type in WirelessInterface_mapget");
399 /* -------------------------------------------------------------------- WirelessInterface_mapset */
400 static int WirelessInterface_mapset(PyObject* self, PyObject* arg, PyObject* val) {
401 if(PyString_Check(arg)) {
402 wiface* wi = (wiface*)(self);
403 char* key = PyString_AsString(arg);
407 memset(&wreq, 0, sizeof(struct iwreq));
410 if(!strncmp(key, "essid", 5)) {
411 if(!Py_SetValString(val, wi->info.b.essid, sizeof(wi->info.b.essid))) {
412 wreq.u.essid.flags = 1;
413 wreq.u.essid.pointer = wi->info.b.essid;
414 wreq.u.essid.length = strlen(wi->info.b.essid) + 1;
417 printf("PYIW DEBUG: iw_set_ext (ESSID) with %s\n", wi->info.b.essid);
420 ret = iw_set_ext(wi->sock, wi->ifname, SIOCSIWESSID, &wreq);
423 printf("PYIW DEBUG: iw_set_ext (ESSID) returned %d\n", ret);
433 else if(!strncmp(key, "wep", 3)) {
434 if(PyString_Check(arg)) {
437 memset(wi->info.b.key, 0, IW_ENCODING_TOKEN_MAX);
440 PyString_AsString(val), wi->info.b.key
443 wreq.u.data.length = len;
444 wreq.u.data.pointer = wi->info.b.key;
446 ret = iw_set_ext(wi->sock, wi->ifname, SIOCSIWENCODE, &wreq);
448 wi->info.b.has_key = 1;
449 wi->info.b.key_size = len;
452 printf("PYIW DEBUG: iw_in_key returned: %d\n", len);
453 printf("PYIW DEBUG: iw_set_ext (ENCODE) returned: %d\n", ret);
460 PyErr_SetString(PyExc_TypeError, "Key must be a string");
466 else if(!strncmp(key, "channel", 7)) {
467 if(!Py_SetValDouble(val, &(wi->info.b.freq), 1.0, 12.0)) {
468 iw_float2freq(wi->info.b.freq, &(wreq.u.freq));
470 if(iw_set_ext(wi->sock, wi->ifname, SIOCSIWFREQ, &wreq)) return -1;
479 else if(!strncmp(key, "mode", 4)) return Py_SetValInt(
480 val, &(wi->info.b.mode), 0, 6
484 PyErr_SetString(PyExc_ValueError, "Bad key in WirelessInterface_mapset");
490 PyErr_SetString(PyExc_TypeError, "Bad key type in WirelessInterface_mapset");
495 /* ------------------------------------------------------------------- WirelessInterface_seqitem */
496 static PyObject* WirelessInterface_seqitem(PyObject* self, int index) {
497 if(index >= 0 && index < WirelessInterfaceNumKeys()) return Py_BuildValue(
498 "s", WirelessInterfaceKeys[index]
504 /* ---------------------------------------------------------------------- WirelessInterface_Scan */
505 static PyObject* WirelessInterface_Scan(wiface* self) {
507 unsigned char* buffer = NULL;
508 int buflen = IW_SCAN_MAX_DATA;
512 int timeout = 10000000;
513 PyObject* scan_list = NULL;
515 has_range = (iw_get_range_info(self->sock, self->ifname, &range) >= 0);
519 wrq.u.data.pointer = NULL;
520 wrq.u.data.flags = 0;
521 wrq.u.data.length = 0;
523 if(iw_set_ext(self->sock, self->ifname, SIOCSIWSCAN, &wrq) < 0) {
525 PyErr_SetString(PyIWError, "Interface doesn't support scanning");
533 timeout -= tv.tv_usec;
543 ret = select(last_fd + 1, &rfds, NULL, NULL, &tv);
546 if(errno == EAGAIN || errno == EINTR) continue;
549 PyErr_SetString(PyIWError, "Unknown scanning error");
556 unsigned char* newbuf;
559 newbuf = realloc(buffer, buflen);
562 if(buffer) free(buffer);
564 PyErr_SetString(PyIWError, "Memory allocation failure in scan");
571 wrq.u.data.pointer = buffer;
572 wrq.u.data.flags = 0;
573 wrq.u.data.length = buflen;
575 if(iw_get_ext(self->sock, self->ifname, SIOCGIWSCAN, &wrq) < 0) {
576 if((errno == E2BIG)) {
577 if(wrq.u.data.length > buflen) buflen = wrq.u.data.length;
583 if(errno == EAGAIN) {
586 timeout -= tv.tv_usec;
588 if(timeout > 0) continue;
593 PyErr_SetString(PyIWError, "Unable to read scan data");
602 if(wrq.u.data.length) {
606 PyObject* scan_dict = NULL;
608 scan_list = PyList_New(0);
610 iw_init_event_stream(&stream, (char*)(buffer), wrq.u.data.length);
613 ret = iw_extract_event_stream(&stream, &iwe, range.we_version_compiled);
617 int sr = WirelessInterface_ScanItem(&iwe, &range, &sd);
623 PyList_Append(scan_list, scan_dict);
624 Py_DECREF(scan_dict);
627 scan_dict = PyDict_New();
629 for(i = 0; i < WirelessInterfaceNumKeys(); i++) {
630 PyMapping_SetItemString(
632 WirelessInterfaceKeys[i],
641 for(i = 0; i < sd.num; i++) {
642 PyMapping_SetItemString(
644 WirelessInterfaceKeys[sd.keys[i]],
648 Py_DECREF(sd.objs[i]);
656 PyList_Append(scan_list, scan_dict);
657 Py_XDECREF(scan_dict);
660 else return Py_BuildValue("[]");
667 /* ------------------------------------------------------------------ WirelessInterface_ScanItem */
668 static int WirelessInterface_ScanItem(iwevent* event, iwrange* range, wifacesd* data) {
669 static char buf[128];
671 memset(data, 0, sizeof(wifacesd));
676 (const struct ether_addr*)(event->u.ap_addr.sa_data),
680 data->keys[0] = PYIW_KE_AP_MAC;
681 data->objs[0] = Py_BuildValue("s", buf);
688 double freq = iw_freq2float(&(event->u.freq));
691 if(freq <= 14.0) channel = iw_channel_to_freq((int)(freq), &freq, range);
692 else channel = iw_freq_to_channel(freq, range);
694 data->keys[0] = PYIW_KE_FREQUENCY;
695 data->keys[1] = PYIW_KE_CHANNEL;
696 data->objs[0] = Py_BuildValue("d", freq);
697 data->objs[1] = Py_BuildValue("i", channel);
704 data->keys[0] = PYIW_KE_MODE;
705 data->objs[0] = Py_BuildValue("s", iw_operation_mode[event->u.mode]);
712 data->keys[0] = PYIW_KE_PROTOCOL;
713 data->objs[0] = Py_BuildValue("s", event->u.name);
720 memcpy(buf, event->u.essid.pointer, event->u.essid.length);
721 buf[event->u.essid.length] = 0x0;
723 data->keys[0] = PYIW_KE_ESSID;
724 data->objs[0] = Py_BuildValue("s", buf);
730 case SIOCGIWENCODE: {
733 if(event->u.data.flags & IW_ENCODE_DISABLED) pybool = Py_False;
734 else pybool = Py_True;
738 data->keys[0] = PYIW_KE_WEP;
739 data->objs[0] = pybool;
746 data->keys[0] = PYIW_KE_BITRATE;
747 data->objs[0] = Py_BuildValue("i", event->u.bitrate.value);
754 data->keys[0] = PYIW_KE_TXPOWER;
755 data->objs[0] = Py_BuildValue("i", event->u.txpower.value);
762 data->keys[0] = PYIW_KE_QUALITY;
763 data->keys[1] = PYIW_KE_LEVEL;
764 data->keys[2] = PYIW_KE_NOISE;
765 data->objs[0] = Py_BuildValue("i", event->u.qual.qual);
766 data->objs[1] = Py_BuildValue("i", event->u.qual.level - 0x100);
767 data->objs[2] = Py_BuildValue("i", event->u.qual.noise - 0x100);
774 PyObject* pytrue = Py_True;
777 data->keys[0] = PYIW_KE_WPA;
778 data->objs[0] = pytrue;
785 memcpy(buf, event->u.data.pointer, event->u.data.length);
786 buf[event->u.data.length] = 0x0;
788 if(strstr(buf, "wpa_ie")) {
789 PyObject* pytrue = Py_True;
792 data->keys[0] = PYIW_KE_WPA;
793 data->objs[0] = pytrue;
797 memset(buf, 0, sizeof(buf));
804 /* -------------------------------------------------------------------- Member/Method Structures */
805 static PyMethodDef module_methods[] = {
807 "version", pyiw_version, METH_NOARGS,
808 "Returns the current PyIW version."
811 "iw_version", pyiw_iw_version, METH_NOARGS,
812 "Returns the current Wireless Extnesions (libiw WE) version."
815 "we_version", pyiw_we_version, METH_NOARGS,
816 "Returns the current Wireless Extensions (kernel-level WE) version."
818 { NULL, NULL, 0, NULL }
821 static PyMethodDef WirelessInterface_methods[] = {
823 "Scan", (PyCFunction)(WirelessInterface_Scan), METH_NOARGS,
824 "This function will attempt to scan any local AP's and return a tuple\n"
825 "of objectes representing the data contained therein."
827 { NULL, NULL, 0, NULL }
830 static PyMappingMethods WirelessInterface_mapping_methods = {
831 WirelessInterface_len, /* length */
832 WirelessInterface_mapget, /* getitem */
833 WirelessInterface_mapset /* setitem */
836 static PySequenceMethods WirelessInterface_sequence_methods = {
837 WirelessInterface_len, /* sq_length */
840 WirelessInterface_seqitem, /* sq_item */
843 0, /* sq_ass_slice */
845 0, /* sq_inplace_concat */
846 0 /* sq_inplace_repeat */
849 /* -------------------------------------------------------------------- PyType_WirelessInterface */
850 static PyTypeObject PyType_WirelessInterface = {
851 PyObject_HEAD_INIT(NULL)
853 "pyiw.WirelessInterface", /* tp_name */
854 sizeof(WirelessInterface), /* tp_basicsize */
856 (destructor)(WirelessInterface_dealloc), /* tp_dealloc */
862 0, /* tp_as_number */
863 &WirelessInterface_sequence_methods, /* tp_as_sequence */
864 &WirelessInterface_mapping_methods, /* tp_as_mapping */
870 0, /* tp_as_buffer */
871 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
875 0, /* tp_richcompare */
876 0, /* tp_weaklistoffset */
879 WirelessInterface_methods, /* tp_methods */
884 0, /* tp_descr_get */
885 0, /* tp_descr_set */
886 0, /* tp_dictoffset */
887 (initproc)(WirelessInterface_init), /* tp_init */
889 PyType_GenericNew, /* tp_new */
895 0, /* tp_subclasses */
900 /* ------------------------------------------------------------------------------------ initpyiw */
901 PyMODINIT_FUNC initpyiw(void) {
904 PyType_Ready(&PyType_WirelessInterface);
906 module = Py_InitModule3("pyiw", module_methods, PYIW_DOC_STRING);
907 PyIWError = PyErr_NewException("pyiw.error", NULL, NULL);
909 Py_INCREF(&PyType_WirelessInterface);
910 Py_INCREF(PyIWError);
912 PyModule_AddObject(module, "WirelessInterface", (PyObject*)(&PyType_WirelessInterface));
913 PyModule_AddObject(module, "error", PyIWError);
916 static PyObject* pyiw_version(PyObject* u1, PyObject* u2) {
917 return Py_BuildValue("(iii)",
924 static PyObject* pyiw_iw_version(PyObject* u1, PyObject* u2) {
925 return Py_BuildValue("i", WE_VERSION);
928 static PyObject* pyiw_we_version(PyObject* u1, PyObject* u2) {
929 return Py_BuildValue("i", iw_get_kernel_we_version());