Logo Search packages:      
Sourcecode: waproamd version File versions  Download package

iwapi.c

/* $Id: iwapi.c 61 2004-01-26 15:56:24Z lennart $ */

/*
 * 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 <errno.h>
#include <assert.h>
#include <string.h>
#include <sys/ioctl.h>

#include <libdaemon/dlog.h>
#include "iwapi.h"

int iw_set_essid(struct interface *i, const char* essid) {
    struct iwreq req;
    char e[IW_ESSID_MAX_SIZE + 1];
    assert(i);

    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", strerror(errno));
        return -1;
    }

    return 0;
}

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);
    req.u.mode = m;

    if (ioctl(i->fd, SIOCSIWMODE, &req) < 0) {
        daemon_log(LOG_ERR, "ioctl(SIOCSIWMODE): %s", strerror(errno));
        return -1;
    }
    
    return 0;
}

/* 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); */
/*     req.u.freq = *f; */

/*     if (ioctl(i->fd, SIOCSIWFREQ, &req) < 0) { */
/*         daemon_log(LOG_ERR, "ioctl(SIOCSIWFREQ): %s", strerror(errno)); */
/*         return -1; */
/*     } */
    
/*     return 0; */
/* } */

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);
    
    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", strerror(errno));
        return -1;
    }
    
    return 0;
}

int iw_scan(struct interface *i) {
    struct iwreq req;
    assert(i);

    daemon_log(LOG_INFO, "Scanning...");
    
    iw_set_mode(i, IW_MODE_INFRA);
    iw_set_essid(i, NULL);
    /* Due to driver issues, the return codes of these function calls are no longer evaluated */

    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", 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", 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");
            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)");
                    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)");
                    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)");
                    return -1;
                }
                
                if ((e->u.mode != IW_MODE_INFRA) &&
                    (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)");
                    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) {
    char c[67];
    assert(i && ap);

    snprint_hw_addr(c, sizeof(c), &ap->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_essid(i, ap->essid);
    //iw_set_freq(i, &ap->freq);
    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", 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", 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", 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) { */
/*         memset(f, 0, sizeof(struct iw_freq)); /\* hostap 0.1.2 fails to report the freq sometimes *\/ */
/*         return 0; */
/*     } */

/*     *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;
    static struct iw_range range;
    int m;

    assert(i);

    if (iw_get_mode(i, &m) < 0)
        return -1;

    if (m != IW_MODE_INFRA)
        return 0;
    
    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");
        return -1;
    }

    memset(&req, 0, sizeof(req));
    strncpy(req.ifr_ifrn.ifrn_name, i->name, IFNAMSIZ);

    memset(&range, 0, sizeof(struct iw_range));
    req.u.data.pointer = (caddr_t) &range;
    req.u.data.length = sizeof(struct iw_range);
    req.u.data.flags = 0;
     
    if (ioctl(i->fd, SIOCGIWRANGE, &req) < 0) {
        fprintf(stderr, "SIOCGIWRANGE failed: %s", strerror(errno));
        return -1;
    }

    /* Test if both qual and level are on their lowest level */
    if (q.qual.qual <= 0 &&
        (q.qual.level > range.max_qual.level ? q.qual.level <= 156 : q.qual.level <= 0))
        return 0;

    
    if (ap) {
        
        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; */
    }
    
    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) && !memcmp(&a->ap, &b->ap, sizeof(struct hw_addr));
}

Generated by  Doxygen 1.6.0   Back to index