SW 개발

[winCE/WM] NDIS 를 이용한 각종 wifi 정보 관련 예제

. . . 2012. 8. 15. 08:52
반응형

각 wifi 의 정보얻기

  • NDIS Interface 를 통해서 각종 Wifi 정보를 얻을때 아래와 같이 사용한다.
  • 해당 코드들은 APP Level 에서 동작한다.

테스트 환경 : Windows Mobile / Windows CE / EVC

NDIS interface 를 이용하기전에.. open / close

아래와 같은 file interface 를 이용한다. NDIS 를 이용하기 위한 핸들은 대부분 전역으로 설정하며 아래와 같이 사용한다. open 과 close 는 아래와 같이 사용한다.

HANDLE g_hNdisUio = NULL;
#define AR6002_ADAPTERNAME _T("AR6K_SD1")
void InitializeNdisUio(void)
{
    if(g_hNdisUio == NULL)
        g_hNdisUio = CreateFile(
                           NDISUIO_DEVICE_NAME,                            //Object name.
                           0x00,                                           //Desired access.
                           0x00,                                           //Share Mode.
                           NULL,                                           //Security Attr
                           OPEN_EXISTING,                                  //Creation Disposition.
                           FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,   //Flag and Attributes..
                           (HANDLE)INVALID_HANDLE_VALUE);

}
void CloseNdisUio( void )
{
    if(g_hNdisUio)
        CloseHandle(g_hNdisUio);
}

이름으로 네트워크 장치찾기

이름으로 네트워크 드라이버를 찾아야 할경우는 아래와 같이 사용한다.

HRESULT FindAdapter( WCHAR* ptcDeviceName )
{
    BOOL fRetVal = FALSE;
    HRESULT hr = E_FAIL;
    WCHAR buf[1024] = {0};
    WCHAR* pAdapterName;
    PNDISUIO_QUERY_BINDING pQueryBinding;
    DWORD dwBytesReturned = 0;
    DWORD i = 0;

    pQueryBinding = (PNDISUIO_QUERY_BINDING)&buf[0];

    for( pQueryBinding->BindingIndex = i; ; ++i )
        {
        fRetVal = DeviceIoControl(
                    g_hNdisUio,
                    IOCTL_NDISUIO_QUERY_BINDING,
                    pQueryBinding,
                    sizeof(NDISUIO_QUERY_BINDING),
                    pQueryBinding,
                    1024,
                    &dwBytesReturned,
                    NULL);

        if( fRetVal == TRUE )
            {
            pAdapterName = (PTCHAR)&buf[pQueryBinding->DeviceNameOffset-1];
            pAdapterName[(pQueryBinding->DeviceNameLength / sizeof(TCHAR)) - 1] = 0x00;

            if( !wcsncmp(ptcDeviceName, pAdapterName, (pQueryBinding->DeviceNameLength)/sizeof(TCHAR)) )
                {
                hr = S_OK;
//AfxMessageBox(_T("Find AR"));
                break;
                }
            }
        else
            {
            break;
            }
        }

    return hr;
}

위의 API는 아래와 같이 사용할때 쓴다..

초기화 함수에서.. 네트워크 장치 찾을때..

if(FindAdapter(AR6002_ADAPTERNAME) == E_FAIL ) {
    AfxMessageBox(_T("can't find AR6001 WLAN Adapter"));
}

SSID 얻어오기

HRESULT getSSID( WCHAR* ptcDeviceName, WCHAR* wSsid, BOOL* bAssociated )
{
    BOOL fRetVal = FALSE;
    HRESULT hr = E_FAIL;
    PNDISUIO_QUERY_OIDpQueryOid = NULL;
    DWORD dwBytesReturned = 0;
    PNDIS_802_11_SSID pSsid;
    UCHAR QueryBuffer[sizeof(NDISUIO_QUERY_OID)+sizeof(NDIS_802_11_SSID)];

    pQueryOid = (PNDISUIO_QUERY_OID)&QueryBuffer[0];
    pQueryOid->ptcDeviceName = ptcDeviceName;
    pQueryOid->Oid = OID_802_11_SSID;

    fRetVal = DeviceIoControl(
                g_hNdisUio,
                IOCTL_NDISUIO_QUERY_OID_VALUE,
                (LPVOID) pQueryOid,
                sizeof(NDISUIO_QUERY_OID) + sizeof(NDIS_802_11_SSID),
                (LPVOID) pQueryOid,
                sizeof(NDISUIO_QUERY_OID) + sizeof(NDIS_802_11_SSID),
                &dwBytesReturned,
                NULL);

    if( fRetVal == TRUE )
    {
        hr = S_OK;
        pSsid = (PNDIS_802_11_SSID)&pQueryOid->Data;
        if( pSsid->SsidLength != 0 )
            {
            *bAssociated = TRUE;
            mbstowcs( wSsid, (const char*)pSsid->Ssid, pSsid->SsidLength );
            wSsid[pSsid->SsidLength] = 0x00;
            }
    }
    else
    {
        wprintf(L"roamctrl: OID_802_11_SSID ioctl fail!\r\n");
        hr = E_FAIL;
    }

    return hr;
}

RSSI 얻어오기

void CROM_CTRLDlg::OnGetRssi() 
{
    // TODO: Add your control notification handler code here
    PUCHAR buffer = NULL;
    NDIS_802_11_RSSI rssi,rssiAbs;
    PNDISUIO_QUERY_OID rssiOid;
    unsigned int lenReq;
    DWORD dwReturnedBytes = 0;

    buffer = (PUCHAR) malloc( sizeof(NDISUIO_QUERY_OID) + sizeof(ULONG) );
    memset( buffer, 0, sizeof(NDISUIO_QUERY_OID) + sizeof(ULONG) );
    lenReq = sizeof(NDISUIO_QUERY_OID) + sizeof(ULONG);
    rssiOid = (NDISUIO_QUERY_OID *)buffer;

    //Send OID_802_11_RSSI Oid to the driver
    rssiOid->Oid = OID_802_11_RSSI;
    rssiOid->ptcDeviceName = AR6002_ADAPTERNAME;

    // Pass the IOCTL to the device
    if (!DeviceIoControl(g_hNdisUio, IOCTL_NDISUIO_QUERY_OID_VALUE, buffer,
                          sizeof(NDISUIO_QUERY_OID), buffer, lenReq,
                              &dwReturnedBytes, NULL)) {
        AfxMessageBox(_T("Error opening device and query"));

        return;
    }

    rssi=(*(NDIS_802_11_RSSI *)(rssiOid->Data));
    //rssiAbs=RSSI_NDIS2ABS(rssi);

    m_rssi.Format(_T("%d"),rssi);

    UpdateData(FALSE);

}

Power State Get / Set

void CROM_CTRLDlg::OnGetpower() 
{
    // TODO: Add your control notification handler code here
    PNDISUIO_QUERY_OID powerModeOid;
    PUCHAR buffer = NULL;
    unsigned int lenReq;
    DWORD dwReturnedBytes = 0;

    buffer = (PUCHAR) malloc( sizeof(NDISUIO_QUERY_OID) + sizeof(UCHAR));
    memset( buffer, 0, sizeof(NDISUIO_SET_OID) + sizeof(UCHAR));
    lenReq = sizeof(NDISUIO_QUERY_OID) + sizeof(UCHAR);
    powerModeOid = (NDISUIO_QUERY_OID *)buffer;

    // Send OID to the driver
    powerModeOid->Oid = OID_802_11_POWER_MODE;
    powerModeOid->ptcDeviceName = AR6002_ADAPTERNAME;

    // Pass the IOCTL to the device
    if(!DeviceIoControl(g_hNdisUio, IOCTL_NDISUIO_QUERY_OID_VALUE, buffer,
                          sizeof(NDISUIO_QUERY_OID), buffer, lenReq,
                              &dwReturnedBytes, NULL)) {
        AfxMessageBox(_T("Get Power Mode failed"));
    }
    else {
        CString str;
        str.Format(_T("%x %x %x %x") , powerModeOid->Data[0] , powerModeOid->Data[1] ,powerModeOid->Data[2] , powerModeOid->Data[3]);
        switch(powerModeOid->Data[0]) {
        case 0:
            m_curpower.Format(_T("CAM mode"));
            break;
        case 1:
            m_curpower.Format(_T("MAX mode"));
            break;
        case 2:
            m_curpower.Format(_T("FAST mode"));
            break;
        default:
            m_curpower.Format(_T("FAIL"));
            break;
        }
        UpdateData(FALSE);
    }

    free(buffer);
}
int SetPowerMode(int mode)
{
    PNDISUIO_SET_OID powerModeOid;
    PUCHAR buffer = NULL;
    DWORD dwReturnedBytes = 0;

    buffer = (PUCHAR) malloc( sizeof(NDISUIO_SET_OID) );
    memset( buffer, 0, sizeof(NDISUIO_SET_OID) );
    powerModeOid = (NDISUIO_SET_OID *)buffer;

    // Send OID to the driver
    powerModeOid->Oid = OID_802_11_POWER_MODE;
    powerModeOid->ptcDeviceName = AR6002_ADAPTERNAME;

    (*(unsigned int *)(powerModeOid->Data)) = mode;

    // Pass the IOCTL to the device
    if (!DeviceIoControl(g_hNdisUio, IOCTL_NDISUIO_SET_OID_VALUE, buffer,
            sizeof(NDISUIO_SET_OID), NULL, 0, &dwReturnedBytes, NULL ) ) {
        AfxMessageBox(_T("Set Power Mode failed"));
        free(buffer);
        return 1;
    }

    free(buffer);
    return 0;
}

Tx Power Level Get / Set

Tx Power Level 의 경우 해당 Network Driver 에서 Tx Power 조정 관련 OID 가 구현되어 있어야 한다.

void CROM_CTRLDlg::OnTxpower() 
{
    // TODO: Add your control notification handler code here
    PNDISUIO_SET_OID txPowerOid;
    PUCHAR buffer = NULL;
    DWORD dwReturnedBytes = 0;

    UpdateData();

    buffer = (PUCHAR) malloc( sizeof(NDISUIO_SET_OID) );
    memset( buffer, 0, sizeof(NDISUIO_SET_OID) );
    txPowerOid = (NDISUIO_SET_OID *)buffer;

    // Send OID to the driver
    txPowerOid->Oid = OID_802_11_TX_POWER_LEVEL;
    txPowerOid->ptcDeviceName = AR6002_ADAPTERNAME;

    (*(unsigned int *)(txPowerOid->Data)) = m_txpower;

    // Pass the IOCTL to the device
    if (!DeviceIoControl(g_hNdisUio, IOCTL_NDISUIO_SET_OID_VALUE, buffer,
            sizeof(NDISUIO_SET_OID), NULL, 0, &dwReturnedBytes, NULL ) ) {
        AfxMessageBox(_T("Set Power Mode failed"));
        free(buffer);
        return;
    }

    free(buffer);
}
void CROM_CTRLDlg::OnGettx() 
{
    // TODO: Add your control notification handler code here
    PNDISUIO_QUERY_OID txPowerOid;
    PUCHAR buffer = NULL;
    unsigned int lenReq;
    DWORD dwReturnedBytes = 0;

    buffer = (PUCHAR) malloc( sizeof(NDISUIO_QUERY_OID) + sizeof(ULONG));
    memset(buffer, 0, sizeof(NDISUIO_SET_OID) + sizeof(ULONG));
    lenReq = sizeof(NDISUIO_QUERY_OID) + sizeof(ULONG);
    txPowerOid = (NDISUIO_QUERY_OID *)buffer;

    // Send OID to the driver
    txPowerOid->Oid = OID_802_11_TX_POWER_LEVEL;
    txPowerOid->ptcDeviceName = AR6002_ADAPTERNAME;

    if(!DeviceIoControl(g_hNdisUio, IOCTL_NDISUIO_QUERY_OID_VALUE, buffer,
                      sizeof(NDISUIO_QUERY_OID), buffer, lenReq,
                          &dwReturnedBytes, NULL)) {
        AfxMessageBox(_T("Get Taget Version failed"));
        return;
    }

    m_txpower = *(ULONG *)&txPowerOid->Data;

    UpdateData(FALSE);

    free(buffer);
}
반응형