您尚未登录。

楼主 #1 2018-12-11 09:18:40

晕哥
管理员
所在地: 微信 whycan_cn
注册时间: 2017-09-06
已发帖子: 9,245
积分: 9197

嵌入式 利用wpa_supplicant编写WIFI、有线网络管理器 转自CSDN, 估计搞带GUI网络编程的朋友都能用上





离线

楼主 #2 2018-12-11 09:20:27

晕哥
管理员
所在地: 微信 whycan_cn
注册时间: 2017-09-06
已发帖子: 9,245
积分: 9197

Re: 嵌入式 利用wpa_supplicant编写WIFI、有线网络管理器 转自CSDN, 估计搞带GUI网络编程的朋友都能用上

嵌入式linux系统中没有内置自动化程度高的管理程序,这个程序就完成根据有线插拔来判断是否启用无线的功能。

qtenetworkmanager.h

#ifndef QTENETWORKMANAGER_H
#define QTENETWORKMANAGER_H

#include <QObject>
#include <QTimer>
#include <QList>
#include "QTEDefine.h"
#include <qthread.h>
#include "QTEDefine.h"

class QTENetworkClearThread : public QThread
{
    Q_OBJECT
public:
    QTENetworkClearThread(QObject* parent = 0) : QThread(parent) {
    }
signals:
    void cleared();
    void notcleared();

    // QThread interface
protected:
    void run();
};

class QTEDhcpThread : public QThread
{
    Q_OBJECT
public:
    QTEDhcpThread(QObject* parent = 0) : QThread(parent) {
    }
    void setnet(QString eth = "eth0") {net=eth;}
signals:
    void passed(QString);
    // QThread interface
protected:
    void run();
private:
    QString net;
};

// thread unsafe
class QTENetworkManager : public QObject
{
    Q_OBJECT
public:
    static QTENetworkManager *Instance(QObject* parent = 0);

    QList<TWifi>& wifiList() { return m_wifiList; }
    inline TWifi currentWifi(){ return m_curWifi; }
    bool setCurrentWifi(QString bssid_mac, QString password = "");
    void setRefresh(bool ref = true) { ref ? m_workTimer->start(5000) : m_workTimer->stop(); }
    void setDHCP(bool bUse = false) { m_bUseDHCP = bUse; }
    void configIPAddress(QString ip, QString mask, QString gw, QString dns);
    QString currentNetName();
    QTimer* workTimer() { return m_workTimer; }
    void saveAddr(QString ip, QString mask, QString gw, QString dns);
    void getAddr(QString& ip, QString& mask, QString& gw, QString& dns);

signals:
    //没有配置就会发送这个信号
    void sigScanning();
    //断开连接的状态
    void sigDisConnected();
    //正在连接的状态
    void sigConnecting();
    //连接成功的状态
    void sigConnected();
    //Wifi列表更新 之上状态改变会影响list中wifi的标志位。
    void sigRefreshed();
    //Wifi状态改变
    void sigStatusChanged(QString status);
    //有线连接上
    void sigLanConnected();
    //有线断开
    void sigLanDisConnected();
    //网络线路连接上
    void sigNetworkClear();
    //网络线路断开
    void sigNetworkNotClear();

private slots:
    void refreshWifiList();
    void refreshWifiStatus();
    void checkLanConnection();
    void DhcpPassed(QString netname);
    void checkNetworkClear();

private:
    explicit QTENetworkManager(QObject *parent = 0);
    void readStatus();
    void restoreWifi();
    bool restartWifi();
    void saveScript();
    void config();

signals:

public slots:
private:
    static QTENetworkManager* _instance;
    QTimer* m_workTimer;
    QList<TWifi> m_wifiList;
    TWifi m_curWifi;
    bool m_bUseDHCP;
    QString m_netName;
    QTEDhcpThread* m_thread;
    QTENetworkClearThread* m_clearThread;
    QString m_status;
};

#endif // QTENETWORKMANAGER_H

qtenetworkmanager.cpp


#include "QTENetworkManager.h"
#include "hnlinux.h"
#include "QTEDefine.h"

QTENetworkManager* QTENetworkManager::_instance = NULL;

QTENetworkManager *QTENetworkManager::Instance(QObject *parent)
{
    if(_instance)
        return _instance;
    _instance = new QTENetworkManager(parent);
    return _instance;
}

bool QTENetworkManager::setCurrentWifi(QString bssid_mac, QString password)
{
    for(QList<TWifi>::Iterator it = m_wifiList.begin();
        it != m_wifiList.end(); it++)
    {
        TWifi wifi = *it;
        if(bssid_mac == wifi[ESSID_BSSID])
        {
            m_status = "";
            m_curWifi = wifi;
            m_curWifi[ESSID_PASS] = password;
            break;
        }
    }

    restoreWifi();

    if(!restartWifi())
        return false;

    return true;
}

void QTENetworkManager::configIPAddress(QString ip, QString mask, QString gw, QString dns)
{
    saveAddr(ip, mask, gw, dns);
    saveScript();
    config();
}

QString QTENetworkManager::currentNetName()
{
    if("eth0" == m_netName)
        return "Wired Lan";
    if("wlan0" == m_netName)
        if("COMPLETED" == m_status)
            return m_curWifi[ESSID_NAME];
    return "";
}

void QTENetworkManager::readStatus()
{
    //从 status 中读取
    char result[MAX_LEN];
    char key[MAX_LEN]; //设置一个合适的长度,以存储每一行输出
    char value[MAX_LEN]; //设置一个合适的长度,以存储每一行输出

    bzero(result, MAX_LEN);
    bzero(key, MAX_LEN);
    bzero(value, MAX_LEN);
    FILE *pp = popen("wpa_cli -iwlan0 status", "r"); //建立管道
    if (!pp)
        return;
    while( fgets(result, sizeof(result), pp) != NULL)
    {
        sscanf(result, "%[^=]=%s", key, value);
        //如果这里不用QString包含,会对比地址
        if(QString("wpa_state") == QString(key)) {
            m_curWifi[ESSID_STATUS] = value;
        } else if(QString("bssid") == QString(key)) {
            m_curWifi[ESSID_BSSID] = value;
        } else if(QString("ssid") == QString(key)) {
            m_curWifi[ESSID_NAME] = value;
        }
    }
    pclose(pp);

    return;
}

void QTENetworkManager::refreshWifiList()
{
    static int scanid = 0;
    if(scanid == 12)
        scanid = 0, system("wpa_cli -iwlan0 scan");
    scanid ++;

    FILE *pp = popen("wpa_cli -iwlan0 scan_r", "r"); //建立管道
    if (!pp)
        return;

    char cmdresult[MAX_LEN]; //设置一个合适的长度,以存储每一行输出
    fgets(cmdresult, sizeof(cmdresult), pp) ; //""

    char bssid[MAX_PATH];
    char frequency[MAX_PATH];
    char signal[MAX_PATH];
    char flag[MAX_PATH];
    char ssid[MAX_PATH];

    m_wifiList.clear();

    while( fgets(cmdresult, sizeof(cmdresult), pp) != NULL)
    {
        sscanf(cmdresult, "%s\t%s\t%s\t%s\t%s\n", bssid, frequency, signal, flag, ssid);

        TWifi wifi;
        wifi[ESSID_NAME] = ssid;
        if( strstr(flag, "WPA"))
            wifi[ESSID_TYPE] = "WPA";
        else
            wifi[ESSID_TYPE] = "WEP";
        if(strstr(flag, "WPA") || strstr(flag, "WEP"))
            wifi[ESSID_ENCRYP] = "YES";
        else
            wifi[ESSID_ENCRYP] = "NO";
        wifi[ESSID_PASS] = "";
        wifi[ESSID_BSSID] = bssid;
        wifi[ESSID_FREQ] = frequency;
        wifi[ESSID_SIGNAL] = signal;
        wifi[ESSID_FLAG] = flag;
        if(wifi[ESSID_BSSID] == m_curWifi[ESSID_BSSID])
            wifi[ESSID_STATUS] = m_curWifi[ESSID_STATUS];
        else
            wifi[ESSID_STATUS] = "";

        m_wifiList.push_back(wifi);

        //pline() << ssid << frequency << signal << flag << bssid << wifi[ESSID_STATUS];
    }

    //pline() << m_wifiList.size();
    pclose(pp); //关闭管道
    emit sigRefreshed();
}

void QTENetworkManager::refreshWifiStatus()
{
    readStatus();

    if(m_status == m_curWifi[ESSID_STATUS])
        return;

    pline() << m_curWifi[ESSID_BSSID] << m_curWifi[ESSID_NAME] << m_curWifi[ESSID_STATUS];

    m_status = m_curWifi[ESSID_STATUS];
    emit sigStatusChanged(m_status);

    if("COMPLETED" == m_status)
        emit sigConnected();
    else if("SCANNING" == m_status)
        emit sigScanning();
    else if("ASSOCIATING" == m_status)
        emit sigConnecting();
    else if("INACTIVE" == m_status)
        emit sigDisConnected();
    else if("4WAY_HANDSHAKE" == m_status)
        emit sigDisConnected();
    else if("DISCONNECTED" == m_status)
        emit sigDisConnected();
}

void QTENetworkManager::checkLanConnection()
{
    char cmdbuf[MAX_PATH];
    char cmdresult[MAX_PATH]; //设置一个合适的长度,以存储每一行输出
    bzero(cmdbuf, MAX_PATH);
    bzero(cmdresult, MAX_PATH);
    sprintf(cmdbuf, "cat /sys/class/net/eth0/carrier");
    FILE *pp = popen(cmdbuf, "r"); //建立管道
    fgets(cmdresult, sizeof(cmdresult), pp); //""
    pclose(pp);

    QString netName = m_netName;

    if(strstr(cmdresult, "0"))
        m_netName = "wlan0";
    else
        m_netName = "eth0";

    if(netName != m_netName)
    {
        config();
        if("wlan0" == m_netName)
            emit sigLanDisConnected();
        else
            emit sigLanConnected();
    }

    return;
}

void QTENetworkManager::DhcpPassed(QString netname)
{
    int sockfd;
    struct ifreq ifr;
    struct sockaddr_in sin;
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1)
    {
        perror("socket");
        return;
    }
    strncpy(ifr.ifr_name, netname.toAscii().data(), IFNAMSIZ);
    ifr.ifr_name[IFNAMSIZ - 1] = 0;
    //ip
    if(ioctl(sockfd, SIOCGIFADDR, &ifr) <0)
        perror("ioctl");
    memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
    QString ip = QString(inet_ntoa(sin.sin_addr));
    //mask
    if (ioctl(sockfd, SIOCGIFNETMASK, &ifr) < 0)
        perror("ioctl");
    memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
    QString mask = QString(inet_ntoa(sin.sin_addr));
    //mac
    if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0)
        perror("ioctl");
    memcpy(&sin, &ifr.ifr_addr, sizeof(sin));
    QString mac = QString(inet_ntoa(sin.sin_addr));
    close(sockfd);
    //gw
    FILE *fp;
    char buf[MAX_PATH];
    char gateway[MAX_PATH];
    bzero(buf, MAX_PATH);
    bzero(gateway, MAX_PATH);
    fp = popen("ip route", "r");
    while(fgets(buf, sizeof(buf), fp) != NULL)
    {
        if(strstr(buf, "default via"))
        {
            sscanf(buf, "%*s%*s%s", gateway);
            break;
        }
    }
    pclose(fp);
    QString gw = gateway;
    //dns
    QFile file("/etc/resolv.conf");
    file.open(QFile::ReadOnly);
    QByteArray nameserver = file.readLine();
    nameserver[nameserver.size()-1] = '\0';
    QList<QByteArray> namelist = nameserver.split(' ');
    QString dns = namelist.size() > 1 ? namelist[1] : gw;
    file.close();

    //pt
    pline() << netname << ip << mask << gw << dns;

    saveAddr(ip, mask, gw, dns);
    saveScript();
}

void QTENetworkManager::checkNetworkClear()
{
    return;
    m_clearThread->start();
}

QTENetworkManager::QTENetworkManager(QObject *parent) :
    QObject(parent)
{
    m_bUseDHCP = false;
    m_clearThread = new QTENetworkClearThread(this);
    connect(m_clearThread, SIGNAL(cleared()), this, SIGNAL(sigNetworkClear()));
    connect(m_clearThread, SIGNAL(notcleared()), this, SIGNAL(sigNetworkNotClear()));
    m_thread = new QTEDhcpThread(this);
    connect(m_thread, SIGNAL(passed(QString)), this, SLOT(DhcpPassed(QString)));
    //检查网线
    //搜索热点
    //刷新连接状态
    m_workTimer = new QTimer(this);
    m_workTimer->setSingleShot(false);
    connect(m_workTimer, SIGNAL(timeout()), this, SLOT(refreshWifiList()));
    connect(m_workTimer, SIGNAL(timeout()), this, SLOT(refreshWifiStatus()));
    connect(m_workTimer, SIGNAL(timeout()), this, SLOT(checkLanConnection()));
    connect(m_workTimer, SIGNAL(timeout()), this, SLOT(checkNetworkClear()));
#ifdef __MIPS_LINUX__
    m_workTimer->start(5000);
    //更新一次,以后一直调用scan_r 5-6s
    system("wpa_cli -iwlan0 scan");
#endif
}

void QTENetworkManager::restoreWifi()
{
    QString name = m_curWifi[ESSID_NAME];
    QString password = m_curWifi[ESSID_PASS];
    QString encryt = m_curWifi[ESSID_ENCRYP];
    QString type = m_curWifi[ESSID_TYPE];

    char cmdbuf[MAX_PATH];
    char cmdresult[MAX_PATH];

    FILE* fp=fopen("/etc/wpa_supplicant.conf", "wb");
    fprintf(fp, "ctrl_interface=/var/run/wpa_supplicant\nctrl_interface_group=0\nap_scan=1\n\n");
    if("NO" == encryt)
    {
        pline() << "None Encryption";
        fprintf(fp, "network={\n\tssid=%s\n\tkey_mgmt=NONE\n\tpriority=5\n}\n", name.toAscii().data());
    }
    else if("WEP" == type)
    {
        pline() << "WEP Encryption";
        fprintf(fp, "network={\n\tssid=\"%s\"\n\tkey_mgmt=NONE\n\twep_key0=%s\n\twep_tx_keyidx=0\n\tpriority=5\n\tauth_alg=SHARED\n}\n",
                name.toAscii().data(), password.toAscii().data());
    }
    else if("WPA" == type)
    {
        pline() << "WPA Encryption";
        bzero(cmdbuf, MAX_PATH);
        bzero(cmdresult, MAX_PATH);
#if 0
        sprintf(cmdbuf, "wpa_passphrase %s %s | awk 'NR==4{print $1}'", name.toAscii().data(), wifiPassword.toAscii().data());
        FILE *pp = popen(cmdbuf, "r"); //建立管道
        fgets(cmdresult, sizeof(cmdresult), pp) ; //""
        pclose(pp);
        fprintf(fp, "network={\n\tssid=\"%s\"\n\tkey_mgmt=WPA-PSK\n\tgroup=TKIP\n\tpairwise=CCMP\n\tproto=WPA\n\t#psk=\"%s\"\n\t%s\tpriority=5\n}\n",
                name, wifiPassword, cmdresult);
#else
        sprintf(cmdbuf, "wpa_passphrase %s %s", name.toAscii().data(), password.toAscii().data());
        FILE *pp = popen(cmdbuf, "r"); //建立管道
        while(fgets(cmdresult, sizeof(cmdresult), pp))  //""
        {
            fputs(cmdresult, fp);
        }
        pclose(pp);
#endif
    }
    fclose(fp);
}

bool QTENetworkManager::restartWifi()
{
    char cmdbuf[MAX_PATH];
    char cmdresult[MAX_PATH]; //设置一个合适的长度,以存储每一行输出
    bzero(cmdbuf, MAX_PATH);
    bzero(cmdresult, MAX_PATH);
    sprintf(cmdbuf, "wpa_cli -iwlan0 reconf");
    FILE *pp = popen(cmdbuf, "r"); //建立管道
    fgets(cmdresult, sizeof(cmdresult), pp); //""
    pclose(pp);

    if(strstr(cmdresult, "FAIL"))
        return false;
    return true;
}

void QTENetworkManager::saveScript()
{
    QString ip, mask, gw, dns;
    getAddr(ip, mask, gw, dns);

    QFile script("./net.sh");
    script.open(QFile::WriteOnly);
    char cmdbuf[MAX_PATH];
    bzero(cmdbuf, MAX_PATH);
    sprintf(cmdbuf, "#!/bin/sh\n\n");
    script.write(cmdbuf);

    bzero(cmdbuf, MAX_PATH);
    sprintf(cmdbuf, "ifconfig eth0 %s netmask %s up\n",
            ip.toAscii().data(),
            mask.toAscii().data());
    script.write(cmdbuf);

    bzero(cmdbuf, MAX_PATH);
    sprintf(cmdbuf, "ifconfig wlan0 %s netmask %s up\n",
            ip.toAscii().data(),
            mask.toAscii().data());
    script.write(cmdbuf);

    bzero(cmdbuf, MAX_PATH);
    sprintf(cmdbuf, "route add default gw %s netmask 0.0.0.0 dev eth0\n",
            gw.toAscii().data());
    script.write(cmdbuf);

    bzero(cmdbuf, MAX_PATH);
    sprintf(cmdbuf, "route add default gw %s netmask 0.0.0.0 dev wlan0\n",
            gw.toAscii().data());
    script.write(cmdbuf);

    bzero(cmdbuf, MAX_PATH);
    sprintf(cmdbuf, "echo nameserver %s > /etc/resolv.conf\n", dns.toAscii().data());
    script.write(cmdbuf);

    bzero(cmdbuf, MAX_PATH);
    sprintf(cmdbuf, "wpa_supplicant -B -Dwext -iwlan0 -c/etc/wpa_supplicant.conf\n");
    script.write(cmdbuf);
    script.close();

    bzero(cmdbuf, MAX_PATH);
    sprintf(cmdbuf, "chmod +x ./net.sh");
    system(cmdbuf);
}

void QTENetworkManager::config()
{
    char cmdbuf[MAX_PATH];
    bzero(cmdbuf, MAX_PATH);
    sprintf(cmdbuf, "ip route | awk '{print $1}' | while read line; do ip route del $line; done");
    system(cmdbuf);
    //system("route");

    if(m_bUseDHCP)
    {
        m_thread->setnet(m_netName);
        m_thread->start();
        return;
    }

    QString ip, mask, gw, dns;
    getAddr(ip, mask, gw, dns);

    pline() << m_netName << ip << mask << gw << dns;

    // add .0 route
    bzero(cmdbuf, MAX_PATH);
    sprintf(cmdbuf, "ifconfig %s 0.0.0.0 up", m_netName.toAscii().data());
    system(cmdbuf);
    bzero(cmdbuf, MAX_PATH);
    sprintf(cmdbuf, "ifconfig %s %s netmask %s",
            m_netName.toAscii().data(),
            ip.toAscii().data(),
            mask.toAscii().data());
    system(cmdbuf);
    QStringList sl = gw.split(".");
    if(sl.size() < 3) { sl.clear(); sl << "0" << "0" << "0" << "0";}
    QString net = QString("%1.%2.%3.0").arg(sl[0]).arg(sl[1]).arg(sl[2]);
#if 0
    //dhcp后 ifconfig up 引发了添加这条route
    //ifconfig 0.0.0.0 也能引发添加这条route
    bzero(cmdbuf, MAX_PATH);
    sprintf(cmdbuf, "route add -net %s netmask %s dev %s",
            net.toAscii().data(),
            mask.toAscii().data(),
            m_netName.toAscii().data());
    system(cmdbuf);
#endif
    bzero(cmdbuf, MAX_PATH);
    sprintf(cmdbuf, "route add default gw %s netmask 0.0.0.0 dev %s",
            gw.toAscii().data(),
            m_netName.toAscii().data());
    system(cmdbuf);
    //system("route");
    bzero(cmdbuf, MAX_PATH);
    sprintf(cmdbuf, "echo nameserver %s > /etc/resolv.conf", dns.toAscii().data());
    system(cmdbuf);
}

void QTENetworkManager::saveAddr(QString ip, QString mask, QString gw, QString dns)
{
    QSettings netSet;
    netSet.setValue("/Network/IP", ip);
    netSet.setValue("/Network/Gateway", gw);
    netSet.setValue("/Network/Mask", mask);
    netSet.setValue("/Network/DNS", dns);
    netSet.sync();
}

void QTENetworkManager::getAddr(QString &ip, QString &mask, QString &gw, QString &dns)
{
    QSettings netSet;
    ip = netSet.value("/Network/IP").toString();
    mask = netSet.value("/Network/Mask").toString();
    gw = netSet.value("/Network/Gateway").toString();
    dns = netSet.value("/Network/DNS").toString();
}

void QTEDhcpThread::run()
{
    char cmdbuf[MAX_PATH];
    bzero(cmdbuf, MAX_PATH);
    sprintf(cmdbuf, "udhcpc -i %s", net.toAscii().data());
    system(cmdbuf);
    emit passed(net);
}


void QTENetworkClearThread::run()
{
    static bool _bclear = false;
    bool bclear = false;
    char cmdbuf[MAX_PATH];
    char cmdresult[MAX_PATH]; //设置一个合适的长度,以存储每一行输出
    bzero(cmdbuf, MAX_PATH);
    bzero(cmdresult, MAX_PATH);
    sprintf(cmdbuf, "ping 222.175.114.244 -w 2 -c 1");
    FILE *pp = popen(cmdbuf, "r"); //建立管道
    while(fgets(cmdresult, sizeof(cmdresult), pp))
    {
        if(strstr(cmdresult, "1 packets transmitted, 1 packets received, 0% packet loss"))
            bclear = true;
        break;
    }
    pclose(pp);

    if(_bclear != bclear)
    {
        if(bclear)
            emit cleared();
        else
            emit notcleared();
        _bclear = bclear;
    }

    return;
}




离线

楼主 #7 2018-12-11 14:51:45

晕哥
管理员
所在地: 微信 whycan_cn
注册时间: 2017-09-06
已发帖子: 9,245
积分: 9197

Re: 嵌入式 利用wpa_supplicant编写WIFI、有线网络管理器 转自CSDN, 估计搞带GUI网络编程的朋友都能用上

apt-get install 直接安装, 试了一下ubuntu的,还是挺不错的:

QQ20181211144936.png

QQ20181211145025.png





离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn