summaryrefslogtreecommitdiffstats
path: root/src/iwapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/iwapi.c')
-rw-r--r--src/iwapi.c159
1 files changed, 152 insertions, 7 deletions
diff --git a/src/iwapi.c b/src/iwapi.c
index ce320c1..2640b06 100644
--- a/src/iwapi.c
+++ b/src/iwapi.c
@@ -30,6 +30,7 @@
int iw_set_essid(struct interface *i, const char* essid) {
struct iwreq req;
char e[IW_ESSID_MAX_SIZE + 1];
+ assert(i && essid);
memset(&req, 0, sizeof(req));
strncpy(req.ifr_ifrn.ifrn_name, i->name, IFNAMSIZ);
@@ -53,6 +54,7 @@ int iw_set_essid(struct interface *i, const char* essid) {
int iw_set_mode(struct interface *i, int m) {
struct iwreq req;
+ assert(i);
memset(&req, 0, sizeof(req));
strncpy(req.ifr_ifrn.ifrn_name, i->name, IFNAMSIZ);
@@ -66,8 +68,9 @@ int iw_set_mode(struct interface *i, int m) {
return 0;
}
-int iw_set_freq(struct interface *i, struct iw_freq *f) {
+int iw_set_freq(struct interface *i, const struct iw_freq *f) {
struct iwreq req;
+ assert(i && f);
memset(&req, 0, sizeof(req));
strncpy(req.ifr_ifrn.ifrn_name, i->name, IFNAMSIZ);
@@ -81,8 +84,9 @@ int iw_set_freq(struct interface *i, struct iw_freq *f) {
return 0;
}
-int iw_set_ap(struct interface *i, struct hw_addr *ap) {
+int iw_set_ap(struct interface *i, const struct hw_addr *ap) {
struct iwreq req;
+ assert(i && ap);
memset(&req, 0, sizeof(req));
strncpy(req.ifr_ifrn.ifrn_name, i->name, IFNAMSIZ);
@@ -100,6 +104,7 @@ int iw_set_ap(struct interface *i, struct hw_addr *ap) {
int iw_scan(struct interface *i) {
struct iwreq req;
+ assert(i);
memset(&req, 0, sizeof(req));
strncpy(req.ifr_ifrn.ifrn_name, i->name, IFNAMSIZ);
@@ -189,10 +194,14 @@ int iw_scan_result(struct interface *i, int (*callback)(struct ap_info* ap)) {
return -1;
}
- if ((e->u.mode != IW_MODE_INFRA) && (e->u.mode != IW_MODE_MASTER))
- f = 0; // Ignore non-APs
- else
+ if ((e->u.mode != IW_MODE_INFRA) &&
+ (e->u.mode != IW_MODE_MASTER) &&
+ (e->u.mode != IW_MODE_ADHOC))
+ f = 0; // Ignore non-APs, non-adhocs
+ else {
f |= 4;
+ ap.adhoc = e->u.mode == IW_MODE_ADHOC;
+ }
break;
@@ -226,10 +235,146 @@ int iw_tune(struct interface *i, struct ap_info *ap) {
assert(i && ap);
/* We are not interested in the return values of these functions due to driver issues */
- iw_set_mode(i, IW_MODE_INFRA);
+ iw_set_mode(i, ap->adhoc ? IW_MODE_ADHOC : IW_MODE_INFRA);
iw_set_essid(i, ap->essid);
iw_set_freq(i, &ap->freq);
- iw_set_ap(i, &ap->ap);
+ if (!ap->adhoc)
+ iw_set_ap(i, &ap->ap);
+
+ return 0;
+}
+
+int iw_get_ap(struct interface *i, struct hw_addr *ap) {
+ struct iwreq req;
+ assert(i && ap);
+
+ memset(&req, 0, sizeof(req));
+ strncpy(req.ifr_ifrn.ifrn_name, i->name, IFNAMSIZ);
+
+ if (ioctl(i->fd, SIOCGIWAP, &req) < 0) {
+ daemon_log(LOG_ERR, "ioctl(SIOCGIWAP): %s\n", strerror(errno));
+ return -1;
+ }
+
+ memcpy(ap->addr, &(req.u.ap_addr.sa_data), ETH_ALEN);
+ return 0;
+}
+
+int iw_get_essid(struct interface *i, char *essid) {
+ struct iwreq req;
+ assert(i && essid);
+
+ memset(&req, 0, sizeof(req));
+ strncpy(req.ifr_ifrn.ifrn_name, i->name, IFNAMSIZ);
+
+ memset(essid, 0, IW_ESSID_MAX_SIZE);
+
+ req.u.essid.pointer = essid;
+ req.u.essid.length = IW_ESSID_MAX_SIZE+1;
+ req.u.essid.flags = 1;
+
+ if (ioctl(i->fd, SIOCGIWESSID, &req) < 0) {
+ daemon_log(LOG_ERR, "ioctl(SIOCGSIWESSID): %s\n", strerror(errno));
+ return -1;
+ }
+
+ essid[IW_ESSID_MAX_SIZE] = 0;
+ return 0;
+}
+
+int iw_get_mode(struct interface *i, int *m) {
+ struct iwreq req;
+ assert(i && m);
+
+ memset(&req, 0, sizeof(req));
+ strncpy(req.ifr_ifrn.ifrn_name, i->name, IFNAMSIZ);
+ req.u.mode = 0;
+
+ if (ioctl(i->fd, SIOCGIWMODE, &req) < 0) {
+ daemon_log(LOG_ERR, "ioctl(SIOCGIWMODE): %s\n", strerror(errno));
+ return -1;
+ }
+
+ *m = req.u.mode;
+ return 0;
+}
+
+int iw_get_freq(struct interface *i, struct iw_freq *f) {
+ struct iwreq req;
+ assert(i && f);
+
+ memset(&req, 0, sizeof(req));
+ strncpy(req.ifr_ifrn.ifrn_name, i->name, IFNAMSIZ);
+
+ if (ioctl(i->fd, SIOCGIWFREQ, &req) < 0) {
+ daemon_log(LOG_ERR, "ioctl(SIOCGIWFREQ): %s\n", strerror(errno));
+ return -1;
+ }
+
+ *f = req.u.freq;
return 0;
}
+
+int iw_assoc(struct interface *i, struct ap_info *ap) {
+ struct hw_addr hw;
+ struct iwreq req;
+ struct iw_statistics q;
+
+ assert(i);
+
+ if (iw_get_ap(i, &hw) < 0)
+ return -1;
+
+ if (!is_assoc_ap(&hw))
+ return 0;
+
+ memset(&req, 0, sizeof(req));
+ strncpy(req.ifr_ifrn.ifrn_name, i->name, IFNAMSIZ);
+
+ req.u.data.pointer = (caddr_t) &q;
+ req.u.data.length = sizeof(q);
+ req.u.data.flags = 1;
+
+ if (ioctl(i->fd, SIOCGIWSTATS, &req) < 0) {
+ daemon_log(LOG_ERR, "Failed to get interface quality\n");
+ return -1;
+ }
+
+ if (q.qual.qual <= 0)
+ return 0;
+
+ if (ap) {
+ int m;
+
+ memset(ap, 0, sizeof(struct ap_info));
+ memcpy(ap->ap.addr, hw.addr, ETH_ALEN);
+
+ if (iw_get_essid(i, ap->essid) < 0)
+ return -1;
+
+ if (iw_get_freq(i, &ap->freq) < 0)
+ return -1;
+
+ if (iw_get_mode(i, &m) < 0)
+ return -1;
+
+ if (m != IW_MODE_INFRA && m != IW_MODE_ADHOC) {
+ daemon_log(LOG_ERR, "Bad interface mode\n");
+ return -1;
+ }
+
+ ap->adhoc = m == IW_MODE_ADHOC;
+ }
+
+ return 1;
+}
+
+int iw_ap_info_equal(const struct ap_info *a, const struct ap_info *b) {
+ assert(a && b);
+
+ return !strcmp(a->essid, b->essid) &&
+ !!a->adhoc == !!b->adhoc &&
+ !memcmp(&a->freq, &b->freq, sizeof(a->freq)) &&
+ (a->adhoc || hw_addr_equal(&a->ap, &b->ap));
+}