summaryrefslogtreecommitdiffstats
path: root/src/iwapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/iwapi.c')
-rw-r--r--src/iwapi.c225
1 files changed, 225 insertions, 0 deletions
diff --git a/src/iwapi.c b/src/iwapi.c
new file mode 100644
index 0000000..5662548
--- /dev/null
+++ b/src/iwapi.c
@@ -0,0 +1,225 @@
+#include <net/if_arp.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include "iwapi.h"
+
+int iw_set_essid(struct interface *i, const char* essid) {
+ struct iwreq req;
+ char e[IW_ESSID_MAX_SIZE + 1];
+
+ memset(&req, 0, sizeof(req));
+ strncpy(req.ifr_ifrn.ifrn_name, i->name, IFNAMSIZ);
+
+ if (essid && *essid) {
+ memset(&e, 0, sizeof(e));
+ strncpy(e, essid, IW_ESSID_MAX_SIZE);
+
+ req.u.essid.pointer = e;
+ req.u.essid.length = strlen(essid) + 1;
+ req.u.essid.flags = 1;
+ }
+
+ if (ioctl(i->fd, SIOCSIWESSID, &req) < 0) {
+ fprintf(stderr, "ioctl(SIOCSIWESSID): %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int iw_set_mode(struct interface *i, int m) {
+ struct iwreq req;
+
+ memset(&req, 0, sizeof(req));
+ strncpy(req.ifr_ifrn.ifrn_name, i->name, IFNAMSIZ);
+ req.u.mode = m;
+
+ if (ioctl(i->fd, SIOCSIWMODE, &req) < 0) {
+ fprintf(stderr, "ioctl(SIOCSIWMODE): %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int iw_set_freq(struct interface *i, struct iw_freq *f) {
+ struct iwreq req;
+
+ memset(&req, 0, sizeof(req));
+ strncpy(req.ifr_ifrn.ifrn_name, i->name, IFNAMSIZ);
+ req.u.freq = *f;
+
+ if (ioctl(i->fd, SIOCSIWFREQ, &req) < 0) {
+ fprintf(stderr, "ioctl(SIOCSIWFREQ): %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int iw_set_ap(struct interface *i, struct hw_addr *ap) {
+ struct iwreq req;
+
+ memset(&req, 0, sizeof(req));
+ strncpy(req.ifr_ifrn.ifrn_name, i->name, IFNAMSIZ);
+
+ req.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(req.u.ap_addr.sa_data, ap->addr, ETH_ALEN);
+
+ if (ioctl(i->fd, SIOCSIWAP, &req) < 0) {
+ fprintf(stderr, "ioctl(SIOCSIWAP): %s\n", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int iw_scan(struct interface *i) {
+ struct iwreq req;
+
+ memset(&req, 0, sizeof(req));
+ strncpy(req.ifr_ifrn.ifrn_name, i->name, IFNAMSIZ);
+
+ req.u.param.flags = IW_SCAN_DEFAULT;
+ req.u.param.value = 0;
+
+ if (ioctl(i->fd, SIOCSIWSCAN, &req) < 0) {
+ fprintf(stderr, "ioctl(SIOCSIWSCAN): %s\n", strerror(errno));
+ return -1;
+ }
+
+// fprintf(stderr, "scan!\n");
+
+ return 0;
+}
+
+
+int iw_scan_result(struct interface *i, int (*callback)(struct ap_info* ap)) {
+ struct ap_info ap;
+ int f, l, hs;
+ struct iwreq req;
+ struct iw_event *e;
+ uint8_t buffer[IW_SCAN_MAX_DATA];
+
+ assert(i && callback);
+
+ memset(&req, 0, sizeof(req));
+ strncpy(req.ifr_ifrn.ifrn_name, i->name, IFNAMSIZ);
+
+ req.u.data.pointer = buffer;
+ req.u.data.flags = 0;
+ req.u.data.length = sizeof(buffer);
+
+ if (ioctl(i->fd, SIOCGIWSCAN, &req) < 0) {
+ if (errno == EAGAIN)
+ return 1;
+
+ fprintf(stderr, "ioctl(SIOCGIWSCAN): %s\n", strerror(errno));
+ return -1;
+ }
+
+// fprintf(stderr, "scan response!\n");
+
+ e = (struct iw_event*) req.u.data.pointer;
+ l = req.u.data.length;
+ f = 0;
+ hs = sizeof(struct iw_event)-sizeof(union iwreq_data);
+ while (l >= sizeof(struct iw_event)) {
+ if (e->len < hs) {
+ fprintf(stderr, "Recieved bogus wireless event\n");
+ return -1;
+ }
+
+ if (!f)
+ memset(&ap, 0, sizeof(ap));
+
+ switch (e->cmd) {
+
+ case SIOCGIWAP:
+
+ f = 1;
+
+ if (e->len < hs + sizeof(struct sockaddr)) {
+ fprintf(stderr, "Corrupt scan result (1)\n");
+ return -1;
+ }
+
+ memcpy(&ap.ap, e->u.ap_addr.sa_data, ETH_ALEN);
+ break;
+
+
+ case SIOCGIWESSID:
+
+ if (e->len < hs + sizeof(struct iw_point)) {
+ fprintf(stderr, "Corrupt scan result (2)\n");
+ return -1;
+ }
+
+ memset(&ap.essid, 0, sizeof(ap.essid));
+ memcpy(&ap.essid, ((uint8_t*) e)+hs+sizeof(struct iw_point), MIN(sizeof(ap.essid)-1, e->len-hs-sizeof(struct iw_point)));
+
+ f |= 2;
+
+ break;
+
+ case SIOCGIWMODE:
+
+ if (e->len < hs + sizeof(__u32)) {
+ fprintf(stderr, "Corrupt scan result (3)\n");
+ return -1;
+ }
+
+ if (e->u.mode != IW_MODE_MASTER)
+ f = 0; // Ignore non-APs
+ else
+ f |= 4;
+
+ break;
+
+ case SIOCGIWFREQ:
+ if (e->len < hs + sizeof(struct iw_freq)) {
+ fprintf(stderr, "Corrupt scan result (4)\n");
+ return -1;
+ }
+
+ memcpy(&ap.freq, &e->u.freq, sizeof(struct iw_freq));
+ f |= 8;
+ break;
+ }
+
+ if (f == 15) {
+
+ //fprintf(stderr, "Scan successful\n");
+
+ if (callback(&ap) < 0)
+ return -1;
+
+ f = 0;
+ }
+
+
+ l -= e->len;
+ e = (struct iw_event*) (((uint8_t*) e) + e->len);
+ }
+ return 0;
+}
+
+int iw_tune(struct interface *i, struct ap_info *ap) {
+ assert(i && ap);
+
+ if (iw_set_mode(i, IW_MODE_INFRA) < 0)
+ return -1;
+
+ if (iw_set_essid(i, ap->essid) < 0)
+ return -1;
+
+ if (iw_set_freq(i, &ap->freq) < 0)
+ return -1;
+
+ if (iw_set_ap(i, &ap->ap) < 0)
+ return -1;
+
+ return 0;
+}