diff options
Diffstat (limited to 'src/iwapi.c')
-rw-r--r-- | src/iwapi.c | 159 |
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)); +} |