/* $Id$ */ /* * This file is part of waproamd. * * waproamd is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * waproamd is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with waproamd; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #include #include #include #include #include #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) { daemon_log(LOG_ERR, "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) { daemon_log(LOG_ERR, "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) { daemon_log(LOG_ERR, "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) { daemon_log(LOG_ERR, "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) { daemon_log(LOG_ERR, "ioctl(SIOCSIWSCAN): %s\n", strerror(errno)); return -1; } 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; daemon_log(LOG_ERR, "ioctl(SIOCGIWSCAN): %s\n", strerror(errno)); return -1; } 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) { daemon_log(LOG_ERR, "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)) { daemon_log(LOG_ERR, "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)) { daemon_log(LOG_ERR, "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)) { daemon_log(LOG_ERR, "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)) { daemon_log(LOG_ERR, "Corrupt scan result (4)\n"); return -1; } memcpy(&ap.freq, &e->u.freq, sizeof(struct iw_freq)); f |= 8; break; } if (f == 15) { 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; }