Initial version

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2020-04-20 09:41:20 +02:00
parent 4fef8f3c34
commit 8438e80891
5 changed files with 264 additions and 0 deletions

3
README.md Normal file
View file

@ -0,0 +1,3 @@
# wlanapi.h Win32 API Wrapper in Golang
See `wlanapi_windows_test.go` for usage example.

8
mksyscall.go Normal file
View file

@ -0,0 +1,8 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (C) 2020 Simon Rozman <simon@rozman.si>. All Rights Reserved.
*/
package wlanapi
//go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go wlanapi_windows.go

122
wlanapi_windows.go Normal file
View file

@ -0,0 +1,122 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (C) 2020 Simon Rozman <simon@rozman.si>. All Rights Reserved.
*/
package wlanapi
import (
"unsafe"
"golang.org/x/sys/windows"
)
//sys wlanFreeMemory(memory unsafe.Pointer) = wlanapi.WlanFreeMemory
//sys wlanOpenHandle(clientVersion uint32, reserved uintptr, negotiatedVersion *uint32, clientHandle *windows.Handle) (ret error) = wlanapi.WlanOpenHandle
//sys wlanCloseHandle(clientHandle windows.Handle, reserved uintptr) (ret error) = wlanapi.WlanCloseHandle
//sys wlanEnumInterfaces(clientHandle windows.Handle, reserved uintptr, interfaceList **InterfaceInfoList) (ret error) = wlanapi.WlanEnumInterfaces
//sys wlanSetProfileEAPXMLUserData(clientHandle windows.Handle, interfaceGUID *windows.GUID, profileName *uint16, flags uint32, eapXMLUserData *uint16, reserved uintptr) (ret error) = wlanapi.WlanSetProfileEapXmlUserData
// InterfaceState is the state of the network (interface).
type InterfaceState uint32
const (
InterfaceStateNotReady InterfaceState = iota
InterfaceStateConnected
InterfaceStateAdHocNetworkFormed
InterfaceStateDisconnecting
InterfaceStateDisconnected
InterfaceStateAssociating
InterfaceStateDiscovering
InterfaceStateAuthenticating
)
const maxNameLength = 256
// InterfaceInfo defines the basic information for an interface
type InterfaceInfo struct {
InterfaceGUID windows.GUID
interfaceDescription [maxNameLength]uint16
State InterfaceState
}
func (ii *InterfaceInfo) InterfaceDescription() string {
return windows.UTF16ToString(ii.interfaceDescription[:])
}
func (ii *InterfaceInfo) SetInterfaceDescription(interfaceDescription string) error {
str, err := windows.UTF16FromString(interfaceDescription)
if err != nil {
return err
}
copy(ii.interfaceDescription[:], str)
return nil
}
// InterfaceInfoList contains an array of NIC interface information.
type InterfaceInfoList struct {
NumberOfItems uint32
Index uint32
}
// Item returns interface info at the given index.
func (iil *InterfaceInfoList) Item(idx uint32) *InterfaceInfo {
if idx > iil.NumberOfItems {
panic("index out of range")
}
addr := uintptr(unsafe.Pointer(iil))
addr += unsafe.Sizeof(InterfaceInfoList{})
iiArray := (*[(1 << 21) - 1]InterfaceInfo)(unsafe.Pointer(addr))
return &(*iiArray)[idx]
}
// Close frees the memory.
func (iil *InterfaceInfoList) Close() {
wlanFreeMemory(unsafe.Pointer(iil))
}
// ClientSession is the client's session handle.
type ClientSession windows.Handle
// CreateClientSession opens a connection to the server.
func CreateClientSession(clientVersion uint32) (session ClientSession, negotiatedVersion uint32, err error) {
var handle windows.Handle
err = wlanOpenHandle(clientVersion, 0, &negotiatedVersion, &handle)
if err != nil {
session = ClientSession(0)
return
}
session = ClientSession(handle)
return
}
// Close closes a connection to the server.
func (session ClientSession) Close() error {
return wlanCloseHandle(windows.Handle(session), 0)
}
// Interfaces enumerates all of the wireless LAN interfaces currently enabled on the local
// computer. Call Close on InterfaceInfoList returned to free resources.
func (session ClientSession) Interfaces() (*InterfaceInfoList, error) {
var iil *InterfaceInfoList
err := wlanEnumInterfaces(windows.Handle(session), 0, &iil)
if err != nil {
return nil, err
}
return iil, nil
}
// SetProfileEAPXMLUserData sets the Extensible Authentication Protocol (EAP) user credentials as
// specified by an XML string. The user credentials apply to a profile on an adapter. These
// credentials can only be used by the caller.
func (session ClientSession) SetProfileEAPXMLUserData(interfaceGUID *windows.GUID, profileName string, flags uint32, eapXMLUserData string) error {
profileName16, err := windows.UTF16PtrFromString(profileName)
if err != nil {
return err
}
eapXMLUserData16, err := windows.UTF16PtrFromString(eapXMLUserData)
if err != nil {
return err
}
return wlanSetProfileEAPXMLUserData(windows.Handle(session), interfaceGUID, profileName16, flags, eapXMLUserData16, 0)
}

47
wlanapi_windows_test.go Normal file
View file

@ -0,0 +1,47 @@
/* SPDX-License-Identifier: MIT
*
* Copyright (C) 2020 Simon Rozman <simon@rozman.si>. All Rights Reserved.
*/
package wlanapi
import (
"testing"
"golang.org/x/sys/windows"
)
func Test(t *testing.T) {
session, version, err := CreateClientSession(2)
if err != nil {
t.Errorf("Error creating client session: %v", err)
}
defer session.Close()
if version < 2 {
t.Errorf("Invalid version: %v", version)
}
ifaces, err := session.Interfaces()
if err != nil {
t.Errorf("Error enumerating interfaces: %v", err)
}
defer ifaces.Close()
for i := uint32(0); i < ifaces.NumberOfItems; i++ {
ii := ifaces.Item(i)
if ii.State == InterfaceStateNotReady {
continue
}
desc := ii.InterfaceDescription()
t.Logf("Interface: %v", desc)
err = session.SetProfileEAPXMLUserData(&ii.InterfaceGUID, "foobar", 0, "<foobar></foobar>")
if err == nil {
t.Errorf("SetProfileEAPXMLUserData error expected")
}
if err != windows.E_NOT_SET {
t.Errorf("SetProfileEAPXMLUserData returned other error than expected: %v", err)
}
}
}

84
zsyscall_windows.go Normal file
View file

@ -0,0 +1,84 @@
// Code generated by 'go generate'; DO NOT EDIT.
package wlanapi
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return nil
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
var (
modwlanapi = windows.NewLazySystemDLL("wlanapi.dll")
procWlanFreeMemory = modwlanapi.NewProc("WlanFreeMemory")
procWlanOpenHandle = modwlanapi.NewProc("WlanOpenHandle")
procWlanCloseHandle = modwlanapi.NewProc("WlanCloseHandle")
procWlanEnumInterfaces = modwlanapi.NewProc("WlanEnumInterfaces")
procWlanSetProfileEapXmlUserData = modwlanapi.NewProc("WlanSetProfileEapXmlUserData")
)
func wlanFreeMemory(memory unsafe.Pointer) {
syscall.Syscall(procWlanFreeMemory.Addr(), 1, uintptr(memory), 0, 0)
return
}
func wlanOpenHandle(clientVersion uint32, reserved uintptr, negotiatedVersion *uint32, clientHandle *windows.Handle) (ret error) {
r0, _, _ := syscall.Syscall6(procWlanOpenHandle.Addr(), 4, uintptr(clientVersion), uintptr(reserved), uintptr(unsafe.Pointer(negotiatedVersion)), uintptr(unsafe.Pointer(clientHandle)), 0, 0)
if r0 != 0 {
ret = syscall.Errno(r0)
}
return
}
func wlanCloseHandle(clientHandle windows.Handle, reserved uintptr) (ret error) {
r0, _, _ := syscall.Syscall(procWlanCloseHandle.Addr(), 2, uintptr(clientHandle), uintptr(reserved), 0)
if r0 != 0 {
ret = syscall.Errno(r0)
}
return
}
func wlanEnumInterfaces(clientHandle windows.Handle, reserved uintptr, interfaceList **InterfaceInfoList) (ret error) {
r0, _, _ := syscall.Syscall(procWlanEnumInterfaces.Addr(), 3, uintptr(clientHandle), uintptr(reserved), uintptr(unsafe.Pointer(interfaceList)))
if r0 != 0 {
ret = syscall.Errno(r0)
}
return
}
func wlanSetProfileEAPXMLUserData(clientHandle windows.Handle, interfaceGUID *windows.GUID, profileName *uint16, flags uint32, eapXMLUserData *uint16, reserved uintptr) (ret error) {
r0, _, _ := syscall.Syscall6(procWlanSetProfileEapXmlUserData.Addr(), 6, uintptr(clientHandle), uintptr(unsafe.Pointer(interfaceGUID)), uintptr(unsafe.Pointer(profileName)), uintptr(flags), uintptr(unsafe.Pointer(eapXMLUserData)), uintptr(reserved))
if r0 != 0 {
ret = syscall.Errno(r0)
}
return
}