WiFi: reworked RPC, CLI, WebClient data structures

This commit is contained in:
MaMe82 2018-09-11 17:43:04 +02:00
parent c7df6b3d01
commit 4a29298b3c
14 changed files with 2074 additions and 1601 deletions

View File

@ -12,7 +12,6 @@ import (
//Empty settings used to store cobra flags
var (
tmpWifiStrReg string = ""
tmpWifiStrChannel uint8 = 0
tmpWifiHideSSID bool = false
@ -20,7 +19,6 @@ var (
tmpWifiDisableNexmon bool = false
tmpWifiSSID string = ""
tmpWifiPSK string = ""
)
/*
@ -50,7 +48,6 @@ var wifiSetAPCmd = &cobra.Command{
Run: cobraWifiSetAP,
}
var wifiSetStaCmd = &cobra.Command{
Use: "sta",
Short: "Configure WiFi interface to join a network as station",
@ -78,16 +75,15 @@ func cobraWifiSetAP(cmd *cobra.Command, args []string) {
return
}
fmt.Printf("Deploying WiFi inteface settings:\n\t%v\n", settings)
err = ClientDeployWifiSettings(StrRemoteHost, StrRemotePort, settings)
state, err := ClientDeployWifiSettings(StrRemoteHost, StrRemotePort, settings)
if err != nil {
fmt.Println(status.Convert(err).Message())
os.Exit(-1) //exit with error
} else {
fmt.Printf("%+v\n", state)
}
return
}
@ -101,18 +97,19 @@ func cobraWifiSetSta(cmd *cobra.Command, args []string) {
return
}
fmt.Printf("Deploying WiFi inteface settings:\n\t%v\n", settings)
err = ClientDeployWifiSettings(StrRemoteHost, StrRemotePort, settings)
state,err := ClientDeployWifiSettings(StrRemoteHost, StrRemotePort, settings)
if err != nil {
fmt.Println(status.Convert(err).Message())
os.Exit(-1) //exit with error
} else {
fmt.Printf("%+v\n", state)
}
return
}
func createWifiAPSettings(channel uint8, reg string, strSSID string, strPSK string, hideSsid bool, nonexmon bool, disabled bool) (settings *pb.WiFiSettings, err error) {
func createWifiAPSettings(channel uint8, reg string, strSSID string, strPSK string, hideSsid bool, nonexmon bool, disabled bool) (settings *pb.WiFi2Settings, err error) {
if channel < 1 || channel > 14 {
return nil, errors.New(fmt.Sprintf("Only 2.4GHz channels between 1 and 14 are supported, but '%d' was given\n", channel))
}
@ -130,29 +127,30 @@ func createWifiAPSettings(channel uint8, reg string, strSSID string, strPSK stri
return nil, errors.New(fmt.Sprintf("A non-empty PSK implies WPA2 and has to have a minimum of 8 characters, but given PSK has '%d' charactres\n", len(strPSK)))
}
settings = &pb.WiFiSettings{
Mode: pb.WiFiSettings_AP,
AuthMode: pb.WiFiSettings_OPEN,
settings = &pb.WiFi2Settings{
WorkingMode: pb.WiFi2WorkingMode_AP,
AuthMode: pb.WiFi2AuthMode_OPEN,
Disabled: disabled,
Reg: reg,
ApChannel: uint32(channel),
ApHideSsid: hideSsid,
BssCfgAP: &pb.BSSCfg{
Regulatory: reg,
Channel: uint32(channel),
HideSsid: hideSsid,
Ap_BSS: &pb.WiFi2BSSCfg{
SSID: strSSID,
PSK: strPSK,
},
DisableNexmon: nonexmon,
BssCfgClient: nil, //not needed
Client_BSSList: []*pb.WiFi2BSSCfg{},
Nexmon: !nonexmon,
Name: "default",
}
if len(strPSK) > 0 {
settings.AuthMode = pb.WiFiSettings_WPA2_PSK //if PSK is given use WPA2
settings.AuthMode = pb.WiFi2AuthMode_WPA2_PSK //if PSK is given use WPA2
}
return settings, err
}
func createWifiStaSettings(reg string, strSSID string, strPSK string, nonexmon bool, disabled bool) (settings *pb.WiFiSettings, err error) {
func createWifiStaSettings(reg string, strSSID string, strPSK string, nonexmon bool, disabled bool) (settings *pb.WiFi2Settings, err error) {
if len(reg) != 2 {
return nil, errors.New(fmt.Sprintf("Regulatory domain has to consist of two uppercase letters (ISO/IEC 3166-1 alpha2), but '%s' was given\n", reg))
}
@ -166,21 +164,25 @@ func createWifiStaSettings(reg string, strSSID string, strPSK string, nonexmon b
return nil, errors.New(fmt.Sprintf("A non-empty PSK implies WPA2 and has to have a minimum of 8 characters, but given PSK has '%d' charactres\n", len(strPSK)))
}
settings = &pb.WiFiSettings{
Mode: pb.WiFiSettings_STA,
AuthMode: pb.WiFiSettings_OPEN,
settings = &pb.WiFi2Settings{
WorkingMode: pb.WiFi2WorkingMode_STA,
AuthMode: pb.WiFi2AuthMode_OPEN,
Disabled: disabled,
Reg: reg,
BssCfgClient: &pb.BSSCfg{
Regulatory: reg,
Client_BSSList: []*pb.WiFi2BSSCfg{
&pb.WiFi2BSSCfg{
SSID: strSSID,
PSK: strPSK,
},
DisableNexmon: nonexmon,
BssCfgAP: nil, //not needed
},
Nexmon: !nonexmon,
Ap_BSS: &pb.WiFi2BSSCfg{}, //not needed
Name: "default",
HideSsid: false,
}
if len(strPSK) > 0 {
settings.AuthMode = pb.WiFiSettings_WPA2_PSK //if PSK is given use WPA2
settings.AuthMode = pb.WiFi2AuthMode_WPA2_PSK //if PSK is given use WPA2
}
return settings, err

View File

@ -258,7 +258,7 @@ func ClientDeployEthernetInterfaceSettings(host string, port string, settings *p
}
func ClientDeployWifiSettings(host string, port string, settings *pb.WiFiSettings) (err error) {
func ClientDeployWifiSettings(host string, port string, settings *pb.WiFi2Settings) (state *pb.WiFi2State, err error) {
// Set up a connection to the server.
address := host + ":" + port
//log.Printf("Connecting %s ...", address)
@ -274,10 +274,8 @@ func ClientDeployWifiSettings(host string, port string, settings *pb.WiFiSetting
ctx, cancel := context.WithTimeout(context.Background(), time.Second * 30)
defer cancel()
_,err = rpcClient.DeployWifiSettings(ctx, settings)
return err
state,err = rpcClient.DeployWiFiSettings2(ctx, settings)
return
}
func ClientHIDRunScript(host string, port string, scriptPath string, timeoutSeconds uint32) (scriptRes *pb.HIDScriptResult, err error) {

1
ntest.go Normal file
View File

@ -0,0 +1 @@
package main

View File

@ -8,6 +8,9 @@
grpc.proto
It has these top-level messages:
WiFi2Settings
WiFi2State
WiFi2BSSCfg
StringMessage
EventRequest
EventValue
@ -33,8 +36,6 @@
DHCPServerSettings
DHCPServerRange
DHCPServerStaticHost
WiFiSettings
BSSCfg
Empty
*/
package P4wnP1_grpc
@ -51,6 +52,53 @@ import (
// is compatible with the jspb package it is being compiled against.
const _ = jspb.JspbPackageIsVersion2
// WiFi2 (distinguish state and settings)
type WiFi2WorkingMode int
const (
WiFi2WorkingMode_UNKNOWN WiFi2WorkingMode = 0
WiFi2WorkingMode_AP WiFi2WorkingMode = 1
WiFi2WorkingMode_STA WiFi2WorkingMode = 2
WiFi2WorkingMode_STA_FAILOVER_AP WiFi2WorkingMode = 3
)
var WiFi2WorkingMode_name = map[int]string{
0: "UNKNOWN",
1: "AP",
2: "STA",
3: "STA_FAILOVER_AP",
}
var WiFi2WorkingMode_value = map[string]int{
"UNKNOWN": 0,
"AP": 1,
"STA": 2,
"STA_FAILOVER_AP": 3,
}
func (x WiFi2WorkingMode) String() string {
return WiFi2WorkingMode_name[int(x)]
}
type WiFi2AuthMode int
const (
WiFi2AuthMode_WPA2_PSK WiFi2AuthMode = 0
WiFi2AuthMode_OPEN WiFi2AuthMode = 1
)
var WiFi2AuthMode_name = map[int]string{
0: "WPA2_PSK",
1: "OPEN",
}
var WiFi2AuthMode_value = map[string]int{
"WPA2_PSK": 0,
"OPEN": 1,
}
func (x WiFi2AuthMode) String() string {
return WiFi2AuthMode_name[int(x)]
}
type EthernetInterfaceSettings_Mode int
const (
@ -77,47 +125,476 @@ func (x EthernetInterfaceSettings_Mode) String() string {
return EthernetInterfaceSettings_Mode_name[int(x)]
}
type WiFiSettings_Mode int
const (
WiFiSettings_AP WiFiSettings_Mode = 0
WiFiSettings_STA WiFiSettings_Mode = 1
WiFiSettings_STA_FAILOVER_AP WiFiSettings_Mode = 2
)
var WiFiSettings_Mode_name = map[int]string{
0: "AP",
1: "STA",
2: "STA_FAILOVER_AP",
}
var WiFiSettings_Mode_value = map[string]int{
"AP": 0,
"STA": 1,
"STA_FAILOVER_AP": 2,
type WiFi2Settings struct {
// Generic
Name string
Disabled bool
Regulatory string
WorkingMode WiFi2WorkingMode
AuthMode WiFi2AuthMode
Channel uint32
Ap_BSS *WiFi2BSSCfg
Client_BSSList []*WiFi2BSSCfg
HideSsid bool
Nexmon bool
}
func (x WiFiSettings_Mode) String() string {
return WiFiSettings_Mode_name[int(x)]
// GetName gets the Name of the WiFi2Settings.
func (m *WiFi2Settings) GetName() (x string) {
if m == nil {
return x
}
return m.Name
}
type WiFiSettings_APAuthMode int
const (
WiFiSettings_WPA2_PSK WiFiSettings_APAuthMode = 0
WiFiSettings_OPEN WiFiSettings_APAuthMode = 1
)
var WiFiSettings_APAuthMode_name = map[int]string{
0: "WPA2_PSK",
1: "OPEN",
// GetDisabled gets the Disabled of the WiFi2Settings.
func (m *WiFi2Settings) GetDisabled() (x bool) {
if m == nil {
return x
}
var WiFiSettings_APAuthMode_value = map[string]int{
"WPA2_PSK": 0,
"OPEN": 1,
return m.Disabled
}
func (x WiFiSettings_APAuthMode) String() string {
return WiFiSettings_APAuthMode_name[int(x)]
// GetRegulatory gets the Regulatory of the WiFi2Settings.
func (m *WiFi2Settings) GetRegulatory() (x string) {
if m == nil {
return x
}
return m.Regulatory
}
// GetWorkingMode gets the WorkingMode of the WiFi2Settings.
func (m *WiFi2Settings) GetWorkingMode() (x WiFi2WorkingMode) {
if m == nil {
return x
}
return m.WorkingMode
}
// GetAuthMode gets the AuthMode of the WiFi2Settings.
func (m *WiFi2Settings) GetAuthMode() (x WiFi2AuthMode) {
if m == nil {
return x
}
return m.AuthMode
}
// GetChannel gets the Channel of the WiFi2Settings.
func (m *WiFi2Settings) GetChannel() (x uint32) {
if m == nil {
return x
}
return m.Channel
}
// GetAp_BSS gets the Ap_BSS of the WiFi2Settings.
func (m *WiFi2Settings) GetAp_BSS() (x *WiFi2BSSCfg) {
if m == nil {
return x
}
return m.Ap_BSS
}
// GetClient_BSSList gets the Client_BSSList of the WiFi2Settings.
func (m *WiFi2Settings) GetClient_BSSList() (x []*WiFi2BSSCfg) {
if m == nil {
return x
}
return m.Client_BSSList
}
// GetHideSsid gets the HideSsid of the WiFi2Settings.
func (m *WiFi2Settings) GetHideSsid() (x bool) {
if m == nil {
return x
}
return m.HideSsid
}
// GetNexmon gets the Nexmon of the WiFi2Settings.
func (m *WiFi2Settings) GetNexmon() (x bool) {
if m == nil {
return x
}
return m.Nexmon
}
// MarshalToWriter marshals WiFi2Settings to the provided writer.
func (m *WiFi2Settings) MarshalToWriter(writer jspb.Writer) {
if m == nil {
return
}
if len(m.Name) > 0 {
writer.WriteString(1, m.Name)
}
if m.Disabled {
writer.WriteBool(2, m.Disabled)
}
if len(m.Regulatory) > 0 {
writer.WriteString(3, m.Regulatory)
}
if int(m.WorkingMode) != 0 {
writer.WriteEnum(4, int(m.WorkingMode))
}
if int(m.AuthMode) != 0 {
writer.WriteEnum(5, int(m.AuthMode))
}
if m.Channel != 0 {
writer.WriteUint32(6, m.Channel)
}
if m.Ap_BSS != nil {
writer.WriteMessage(7, func() {
m.Ap_BSS.MarshalToWriter(writer)
})
}
for _, msg := range m.Client_BSSList {
writer.WriteMessage(8, func() {
msg.MarshalToWriter(writer)
})
}
if m.HideSsid {
writer.WriteBool(9, m.HideSsid)
}
if m.Nexmon {
writer.WriteBool(13, m.Nexmon)
}
return
}
// Marshal marshals WiFi2Settings to a slice of bytes.
func (m *WiFi2Settings) Marshal() []byte {
writer := jspb.NewWriter()
m.MarshalToWriter(writer)
return writer.GetResult()
}
// UnmarshalFromReader unmarshals a WiFi2Settings from the provided reader.
func (m *WiFi2Settings) UnmarshalFromReader(reader jspb.Reader) *WiFi2Settings {
for reader.Next() {
if m == nil {
m = &WiFi2Settings{}
}
switch reader.GetFieldNumber() {
case 1:
m.Name = reader.ReadString()
case 2:
m.Disabled = reader.ReadBool()
case 3:
m.Regulatory = reader.ReadString()
case 4:
m.WorkingMode = WiFi2WorkingMode(reader.ReadEnum())
case 5:
m.AuthMode = WiFi2AuthMode(reader.ReadEnum())
case 6:
m.Channel = reader.ReadUint32()
case 7:
reader.ReadMessage(func() {
m.Ap_BSS = m.Ap_BSS.UnmarshalFromReader(reader)
})
case 8:
reader.ReadMessage(func() {
m.Client_BSSList = append(m.Client_BSSList, new(WiFi2BSSCfg).UnmarshalFromReader(reader))
})
case 9:
m.HideSsid = reader.ReadBool()
case 13:
m.Nexmon = reader.ReadBool()
default:
reader.SkipField()
}
}
return m
}
// Unmarshal unmarshals a WiFi2Settings from a slice of bytes.
func (m *WiFi2Settings) Unmarshal(rawBytes []byte) (*WiFi2Settings, error) {
reader := jspb.NewReader(rawBytes)
m = m.UnmarshalFromReader(reader)
if err := reader.Err(); err != nil {
return nil, err
}
return m, nil
}
type WiFi2State struct {
Name string
Regulatory string
WorkingMode WiFi2WorkingMode
AuthMode WiFi2AuthMode
Channel uint32
Bss *WiFi2BSSCfg
HideSsid bool
Nexmon bool
Disabled bool
}
// GetName gets the Name of the WiFi2State.
func (m *WiFi2State) GetName() (x string) {
if m == nil {
return x
}
return m.Name
}
// GetRegulatory gets the Regulatory of the WiFi2State.
func (m *WiFi2State) GetRegulatory() (x string) {
if m == nil {
return x
}
return m.Regulatory
}
// GetWorkingMode gets the WorkingMode of the WiFi2State.
func (m *WiFi2State) GetWorkingMode() (x WiFi2WorkingMode) {
if m == nil {
return x
}
return m.WorkingMode
}
// GetAuthMode gets the AuthMode of the WiFi2State.
func (m *WiFi2State) GetAuthMode() (x WiFi2AuthMode) {
if m == nil {
return x
}
return m.AuthMode
}
// GetChannel gets the Channel of the WiFi2State.
func (m *WiFi2State) GetChannel() (x uint32) {
if m == nil {
return x
}
return m.Channel
}
// GetBss gets the Bss of the WiFi2State.
func (m *WiFi2State) GetBss() (x *WiFi2BSSCfg) {
if m == nil {
return x
}
return m.Bss
}
// GetHideSsid gets the HideSsid of the WiFi2State.
func (m *WiFi2State) GetHideSsid() (x bool) {
if m == nil {
return x
}
return m.HideSsid
}
// GetNexmon gets the Nexmon of the WiFi2State.
func (m *WiFi2State) GetNexmon() (x bool) {
if m == nil {
return x
}
return m.Nexmon
}
// GetDisabled gets the Disabled of the WiFi2State.
func (m *WiFi2State) GetDisabled() (x bool) {
if m == nil {
return x
}
return m.Disabled
}
// MarshalToWriter marshals WiFi2State to the provided writer.
func (m *WiFi2State) MarshalToWriter(writer jspb.Writer) {
if m == nil {
return
}
if len(m.Name) > 0 {
writer.WriteString(1, m.Name)
}
if len(m.Regulatory) > 0 {
writer.WriteString(2, m.Regulatory)
}
if int(m.WorkingMode) != 0 {
writer.WriteEnum(3, int(m.WorkingMode))
}
if int(m.AuthMode) != 0 {
writer.WriteEnum(4, int(m.AuthMode))
}
if m.Channel != 0 {
writer.WriteUint32(5, m.Channel)
}
if m.Bss != nil {
writer.WriteMessage(6, func() {
m.Bss.MarshalToWriter(writer)
})
}
if m.HideSsid {
writer.WriteBool(7, m.HideSsid)
}
if m.Nexmon {
writer.WriteBool(8, m.Nexmon)
}
if m.Disabled {
writer.WriteBool(9, m.Disabled)
}
return
}
// Marshal marshals WiFi2State to a slice of bytes.
func (m *WiFi2State) Marshal() []byte {
writer := jspb.NewWriter()
m.MarshalToWriter(writer)
return writer.GetResult()
}
// UnmarshalFromReader unmarshals a WiFi2State from the provided reader.
func (m *WiFi2State) UnmarshalFromReader(reader jspb.Reader) *WiFi2State {
for reader.Next() {
if m == nil {
m = &WiFi2State{}
}
switch reader.GetFieldNumber() {
case 1:
m.Name = reader.ReadString()
case 2:
m.Regulatory = reader.ReadString()
case 3:
m.WorkingMode = WiFi2WorkingMode(reader.ReadEnum())
case 4:
m.AuthMode = WiFi2AuthMode(reader.ReadEnum())
case 5:
m.Channel = reader.ReadUint32()
case 6:
reader.ReadMessage(func() {
m.Bss = m.Bss.UnmarshalFromReader(reader)
})
case 7:
m.HideSsid = reader.ReadBool()
case 8:
m.Nexmon = reader.ReadBool()
case 9:
m.Disabled = reader.ReadBool()
default:
reader.SkipField()
}
}
return m
}
// Unmarshal unmarshals a WiFi2State from a slice of bytes.
func (m *WiFi2State) Unmarshal(rawBytes []byte) (*WiFi2State, error) {
reader := jspb.NewReader(rawBytes)
m = m.UnmarshalFromReader(reader)
if err := reader.Err(); err != nil {
return nil, err
}
return m, nil
}
type WiFi2BSSCfg struct {
SSID string
PSK string
}
// GetSSID gets the SSID of the WiFi2BSSCfg.
func (m *WiFi2BSSCfg) GetSSID() (x string) {
if m == nil {
return x
}
return m.SSID
}
// GetPSK gets the PSK of the WiFi2BSSCfg.
func (m *WiFi2BSSCfg) GetPSK() (x string) {
if m == nil {
return x
}
return m.PSK
}
// MarshalToWriter marshals WiFi2BSSCfg to the provided writer.
func (m *WiFi2BSSCfg) MarshalToWriter(writer jspb.Writer) {
if m == nil {
return
}
if len(m.SSID) > 0 {
writer.WriteString(1, m.SSID)
}
if len(m.PSK) > 0 {
writer.WriteString(2, m.PSK)
}
return
}
// Marshal marshals WiFi2BSSCfg to a slice of bytes.
func (m *WiFi2BSSCfg) Marshal() []byte {
writer := jspb.NewWriter()
m.MarshalToWriter(writer)
return writer.GetResult()
}
// UnmarshalFromReader unmarshals a WiFi2BSSCfg from the provided reader.
func (m *WiFi2BSSCfg) UnmarshalFromReader(reader jspb.Reader) *WiFi2BSSCfg {
for reader.Next() {
if m == nil {
m = &WiFi2BSSCfg{}
}
switch reader.GetFieldNumber() {
case 1:
m.SSID = reader.ReadString()
case 2:
m.PSK = reader.ReadString()
default:
reader.SkipField()
}
}
return m
}
// Unmarshal unmarshals a WiFi2BSSCfg from a slice of bytes.
func (m *WiFi2BSSCfg) Unmarshal(rawBytes []byte) (*WiFi2BSSCfg, error) {
reader := jspb.NewReader(rawBytes)
m = m.UnmarshalFromReader(reader)
if err := reader.Err(); err != nil {
return nil, err
}
return m, nil
}
// Alive check
@ -2598,276 +3075,6 @@ func (m *DHCPServerStaticHost) Unmarshal(rawBytes []byte) (*DHCPServerStaticHost
return m, nil
}
// WiFi
type WiFiSettings struct {
Disabled bool
Reg string
Mode WiFiSettings_Mode
AuthMode WiFiSettings_APAuthMode
ApChannel uint32
BssCfgAP *BSSCfg
BssCfgClient *BSSCfg
ApHideSsid bool
DisableNexmon bool
}
// GetDisabled gets the Disabled of the WiFiSettings.
func (m *WiFiSettings) GetDisabled() (x bool) {
if m == nil {
return x
}
return m.Disabled
}
// GetReg gets the Reg of the WiFiSettings.
func (m *WiFiSettings) GetReg() (x string) {
if m == nil {
return x
}
return m.Reg
}
// GetMode gets the Mode of the WiFiSettings.
func (m *WiFiSettings) GetMode() (x WiFiSettings_Mode) {
if m == nil {
return x
}
return m.Mode
}
// GetAuthMode gets the AuthMode of the WiFiSettings.
func (m *WiFiSettings) GetAuthMode() (x WiFiSettings_APAuthMode) {
if m == nil {
return x
}
return m.AuthMode
}
// GetApChannel gets the ApChannel of the WiFiSettings.
func (m *WiFiSettings) GetApChannel() (x uint32) {
if m == nil {
return x
}
return m.ApChannel
}
// GetBssCfgAP gets the BssCfgAP of the WiFiSettings.
func (m *WiFiSettings) GetBssCfgAP() (x *BSSCfg) {
if m == nil {
return x
}
return m.BssCfgAP
}
// GetBssCfgClient gets the BssCfgClient of the WiFiSettings.
func (m *WiFiSettings) GetBssCfgClient() (x *BSSCfg) {
if m == nil {
return x
}
return m.BssCfgClient
}
// GetApHideSsid gets the ApHideSsid of the WiFiSettings.
func (m *WiFiSettings) GetApHideSsid() (x bool) {
if m == nil {
return x
}
return m.ApHideSsid
}
// GetDisableNexmon gets the DisableNexmon of the WiFiSettings.
func (m *WiFiSettings) GetDisableNexmon() (x bool) {
if m == nil {
return x
}
return m.DisableNexmon
}
// MarshalToWriter marshals WiFiSettings to the provided writer.
func (m *WiFiSettings) MarshalToWriter(writer jspb.Writer) {
if m == nil {
return
}
if m.Disabled {
writer.WriteBool(1, m.Disabled)
}
if len(m.Reg) > 0 {
writer.WriteString(2, m.Reg)
}
if int(m.Mode) != 0 {
writer.WriteEnum(3, int(m.Mode))
}
if int(m.AuthMode) != 0 {
writer.WriteEnum(4, int(m.AuthMode))
}
if m.ApChannel != 0 {
writer.WriteUint32(5, m.ApChannel)
}
if m.BssCfgAP != nil {
writer.WriteMessage(6, func() {
m.BssCfgAP.MarshalToWriter(writer)
})
}
if m.BssCfgClient != nil {
writer.WriteMessage(7, func() {
m.BssCfgClient.MarshalToWriter(writer)
})
}
if m.ApHideSsid {
writer.WriteBool(8, m.ApHideSsid)
}
if m.DisableNexmon {
writer.WriteBool(10, m.DisableNexmon)
}
return
}
// Marshal marshals WiFiSettings to a slice of bytes.
func (m *WiFiSettings) Marshal() []byte {
writer := jspb.NewWriter()
m.MarshalToWriter(writer)
return writer.GetResult()
}
// UnmarshalFromReader unmarshals a WiFiSettings from the provided reader.
func (m *WiFiSettings) UnmarshalFromReader(reader jspb.Reader) *WiFiSettings {
for reader.Next() {
if m == nil {
m = &WiFiSettings{}
}
switch reader.GetFieldNumber() {
case 1:
m.Disabled = reader.ReadBool()
case 2:
m.Reg = reader.ReadString()
case 3:
m.Mode = WiFiSettings_Mode(reader.ReadEnum())
case 4:
m.AuthMode = WiFiSettings_APAuthMode(reader.ReadEnum())
case 5:
m.ApChannel = reader.ReadUint32()
case 6:
reader.ReadMessage(func() {
m.BssCfgAP = m.BssCfgAP.UnmarshalFromReader(reader)
})
case 7:
reader.ReadMessage(func() {
m.BssCfgClient = m.BssCfgClient.UnmarshalFromReader(reader)
})
case 8:
m.ApHideSsid = reader.ReadBool()
case 10:
m.DisableNexmon = reader.ReadBool()
default:
reader.SkipField()
}
}
return m
}
// Unmarshal unmarshals a WiFiSettings from a slice of bytes.
func (m *WiFiSettings) Unmarshal(rawBytes []byte) (*WiFiSettings, error) {
reader := jspb.NewReader(rawBytes)
m = m.UnmarshalFromReader(reader)
if err := reader.Err(); err != nil {
return nil, err
}
return m, nil
}
type BSSCfg struct {
SSID string
PSK string
}
// GetSSID gets the SSID of the BSSCfg.
func (m *BSSCfg) GetSSID() (x string) {
if m == nil {
return x
}
return m.SSID
}
// GetPSK gets the PSK of the BSSCfg.
func (m *BSSCfg) GetPSK() (x string) {
if m == nil {
return x
}
return m.PSK
}
// MarshalToWriter marshals BSSCfg to the provided writer.
func (m *BSSCfg) MarshalToWriter(writer jspb.Writer) {
if m == nil {
return
}
if len(m.SSID) > 0 {
writer.WriteString(1, m.SSID)
}
if len(m.PSK) > 0 {
writer.WriteString(2, m.PSK)
}
return
}
// Marshal marshals BSSCfg to a slice of bytes.
func (m *BSSCfg) Marshal() []byte {
writer := jspb.NewWriter()
m.MarshalToWriter(writer)
return writer.GetResult()
}
// UnmarshalFromReader unmarshals a BSSCfg from the provided reader.
func (m *BSSCfg) UnmarshalFromReader(reader jspb.Reader) *BSSCfg {
for reader.Next() {
if m == nil {
m = &BSSCfg{}
}
switch reader.GetFieldNumber() {
case 1:
m.SSID = reader.ReadString()
case 2:
m.PSK = reader.ReadString()
default:
reader.SkipField()
}
}
return m
}
// Unmarshal unmarshals a BSSCfg from a slice of bytes.
func (m *BSSCfg) Unmarshal(rawBytes []byte) (*BSSCfg, error) {
reader := jspb.NewReader(rawBytes)
m = m.UnmarshalFromReader(reader)
if err := reader.Err(); err != nil {
return nil, err
}
return m, nil
}
type Empty struct {
}
@ -2939,9 +3146,6 @@ type P4WNP1Client interface {
DeployEthernetInterfaceSettings(ctx context.Context, in *EthernetInterfaceSettings, opts ...grpcweb.CallOption) (*Empty, error)
GetAllDeployedEthernetInterfaceSettings(ctx context.Context, in *Empty, opts ...grpcweb.CallOption) (*DeployedEthernetInterfaceSettings, error)
GetDeployedEthernetInterfaceSettings(ctx context.Context, in *StringMessage, opts ...grpcweb.CallOption) (*EthernetInterfaceSettings, error)
// WiFi
DeployWifiSettings(ctx context.Context, in *WiFiSettings, opts ...grpcweb.CallOption) (*Empty, error)
GetDeployedWifiSettings(ctx context.Context, in *Empty, opts ...grpcweb.CallOption) (*WiFiSettings, error)
// HIDScript / job management
HIDRunScript(ctx context.Context, in *HIDScriptRequest, opts ...grpcweb.CallOption) (*HIDScriptResult, error)
HIDRunScriptJob(ctx context.Context, in *HIDScriptRequest, opts ...grpcweb.CallOption) (*HIDScriptJob, error)
@ -2959,6 +3163,9 @@ type P4WNP1Client interface {
EventListen(ctx context.Context, in *EventRequest, opts ...grpcweb.CallOption) (P4WNP1_EventListenClient, error)
// Alive check
EchoRequest(ctx context.Context, in *StringMessage, opts ...grpcweb.CallOption) (*StringMessage, error)
DeployWiFiSettings2(ctx context.Context, in *WiFi2Settings, opts ...grpcweb.CallOption) (*WiFi2State, error)
GetWiFiState2(ctx context.Context, in *Empty, opts ...grpcweb.CallOption) (*WiFi2State, error)
ListenWiFiStateChanges2(ctx context.Context, in *Empty, opts ...grpcweb.CallOption) (*WiFi2State, error)
}
type p4WNP1Client struct {
@ -3062,24 +3269,6 @@ func (c *p4WNP1Client) GetDeployedEthernetInterfaceSettings(ctx context.Context,
return new(EthernetInterfaceSettings).Unmarshal(resp)
}
func (c *p4WNP1Client) DeployWifiSettings(ctx context.Context, in *WiFiSettings, opts ...grpcweb.CallOption) (*Empty, error) {
resp, err := c.client.RPCCall(ctx, "DeployWifiSettings", in.Marshal(), opts...)
if err != nil {
return nil, err
}
return new(Empty).Unmarshal(resp)
}
func (c *p4WNP1Client) GetDeployedWifiSettings(ctx context.Context, in *Empty, opts ...grpcweb.CallOption) (*WiFiSettings, error) {
resp, err := c.client.RPCCall(ctx, "GetDeployedWifiSettings", in.Marshal(), opts...)
if err != nil {
return nil, err
}
return new(WiFiSettings).Unmarshal(resp)
}
func (c *p4WNP1Client) HIDRunScript(ctx context.Context, in *HIDScriptRequest, opts ...grpcweb.CallOption) (*HIDScriptResult, error) {
resp, err := c.client.RPCCall(ctx, "HIDRunScript", in.Marshal(), opts...)
if err != nil {
@ -3219,3 +3408,30 @@ func (c *p4WNP1Client) EchoRequest(ctx context.Context, in *StringMessage, opts
return new(StringMessage).Unmarshal(resp)
}
func (c *p4WNP1Client) DeployWiFiSettings2(ctx context.Context, in *WiFi2Settings, opts ...grpcweb.CallOption) (*WiFi2State, error) {
resp, err := c.client.RPCCall(ctx, "DeployWiFiSettings2", in.Marshal(), opts...)
if err != nil {
return nil, err
}
return new(WiFi2State).Unmarshal(resp)
}
func (c *p4WNP1Client) GetWiFiState2(ctx context.Context, in *Empty, opts ...grpcweb.CallOption) (*WiFi2State, error) {
resp, err := c.client.RPCCall(ctx, "GetWiFiState2", in.Marshal(), opts...)
if err != nil {
return nil, err
}
return new(WiFi2State).Unmarshal(resp)
}
func (c *p4WNP1Client) ListenWiFiStateChanges2(ctx context.Context, in *Empty, opts ...grpcweb.CallOption) (*WiFi2State, error) {
resp, err := c.client.RPCCall(ctx, "ListenWiFiStateChanges2", in.Marshal(), opts...)
if err != nil {
return nil, err
}
return new(WiFi2State).Unmarshal(resp)
}

File diff suppressed because it is too large Load Diff

View File

@ -17,10 +17,11 @@ service P4WNP1 {
rpc GetAllDeployedEthernetInterfaceSettings (Empty) returns (DeployedEthernetInterfaceSettings) { }
rpc GetDeployedEthernetInterfaceSettings (StringMessage) returns (EthernetInterfaceSettings) { } //StringMessage has to contain the interface name
/*
// WiFi
rpc DeployWifiSettings(WiFiSettings) returns (Empty) {}
rpc DeployWifiSettings (WiFiSettings) returns (WiFiConnectionState) {}
rpc GetDeployedWifiSettings (Empty) returns (WiFiSettings) {}
*/
//HIDScript / job management
rpc HIDRunScript (HIDScriptRequest) returns (HIDScriptResult) { }
rpc HIDRunScriptJob (HIDScriptRequest) returns (HIDScriptJob) { }
@ -41,8 +42,65 @@ service P4WNP1 {
//Alive check
rpc EchoRequest (StringMessage) returns (StringMessage) { }
rpc DeployWiFiSettings2 (WiFi2Settings) returns (WiFi2State) {}
rpc GetWiFiState2 (Empty) returns (WiFi2State) {}
rpc ListenWiFiStateChanges2 (Empty) returns (WiFi2State) {}
// ToDo: Template requests (store, load, listStored)
}
/* WiFi2 (distinguish state and settings) */
enum WiFi2WorkingMode {
UNKNOWN = 0;
AP = 1; //acts as access point
STA = 2; //acts as station for an existing access point
STA_FAILOVER_AP = 3; //acts as station, if connection to the given AP isn't possible spawns an own AP
}
enum WiFi2AuthMode {
WPA2_PSK = 0; //AP uses WPA2 pre-shared key
OPEN = 1; //Open System Authentication (no authentication)
}
message WiFi2Settings {
/* Generic */
string name = 1; //for template storage
bool disabled = 2; //disabled means neither hostapd, nor wpa_supplicant are running, the interface could still be enabled
string regulatory = 3; //Regulatory domain per ISO/IEC 3166-1 alpha2
WiFi2WorkingMode working_mode = 4;
WiFi2AuthMode auth_mode = 5;
uint32 channel = 6;
WiFi2BSSCfg ap_BSS = 7; //SSID of AP to spawn + PSK if needed
repeated WiFi2BSSCfg client_BSS_list = 8; //SSID of Infra to join + PSK if needed
bool hide_ssid = 9; //if true, SSID gets hidden for spawned AP
bool nexmon = 13;
}
message WiFi2State {
string name = 1; //name of template in use
string regulatory = 2; //Regulatory domain per ISO/IEC 3166-1 alpha2
WiFi2WorkingMode working_mode = 3;
WiFi2AuthMode auth_mode = 4;
uint32 channel = 5;
WiFi2BSSCfg bss = 6; //SSID currently connected (STA) or spawned (AP)
bool hide_ssid = 7;
bool nexmon = 8;
bool disabled = 9;
}
message WiFi2BSSCfg {
string SSID = 1;
string PSK = 2;
}
/* Alive check */
message StringMessage {
string msg = 1;
@ -214,45 +272,12 @@ message DHCPServerRange {
string leaseTime = 3;
}
//Used for static leases
message DHCPServerStaticHost {
string mac = 1;
string ip = 2;
}
/* End DHCP */
/* WiFi */
message WiFiSettings {
enum Mode {
AP = 0; //acts as access point
STA = 1; //acts as station for an existing access point
STA_FAILOVER_AP = 2; //acts as station, if connection to the given AP isn't possible spawns an own AP
message Empty {
}
enum APAuthMode {
WPA2_PSK = 0; //AP uses WPA2 pre-shared key
OPEN = 1; //Open System Authentication (no authentication)
}
bool disabled = 1;
string reg = 2; //Regulatory domain per ISO/IEC 3166-1 alpha2
Mode mode = 3;
APAuthMode auth_mode = 4;
uint32 ap_channel = 5;
BSSCfg BssCfgAP = 6; //SSID of AP to spawn + PSK if needed
BSSCfg BssCfgClient = 7; //SSID of Infra to join + PSK if needed
bool ap_hide_ssid = 8; //if true, SSID gets hidden for spawned AP
bool disable_nexmon = 10; //if true, legacy driver / firmware is used instead of nexmon
}
message BSSCfg {
string SSID = 1;
string PSK = 2;
}
/* End WiFI */
message Empty {}

View File

@ -2,58 +2,399 @@ package service
import (
pb "github.com/mame82/P4wnP1_go/proto"
"log"
"github.com/mame82/P4wnP1_go/netlink"
"sync"
"os/exec"
"github.com/mame82/P4wnP1_go/service/util"
"net"
"errors"
"fmt"
"os/exec"
"strings"
"os"
"io/ioutil"
"syscall"
"log"
"time"
"sync"
"syscall"
"net"
"io/ioutil"
"os"
"regexp"
"strconv"
)
const (
wifi_if_name string = "wlan0"
)
//ToDo: big to do ... move all the shitty command tool line wrapping/parsing (iw, hostapd, wpa_supplicant etc.) to dedicated netlink/nl80211 implementation
//VERY LOW PRIORITY, as this basically means reimplementing the whole toolset for a way too small benefit
type WiFiAuthMode int
const (
WiFiAuthMode_OPEN WiFiAuthMode = iota
//WiFiAuthMode_WEP
WiFiAuthMode_WPA_PSK
WiFiAuthMode_WPA2_PSK
WiFiAuthMode_UNSUPPORTED
)
const (
WPA_SUPPLICANT_CONNECT_TIMEOUT = time.Second * 20
)
type WifiState struct {
mutexSettings *sync.Mutex
Settings *pb.WiFiSettings
CmdWpaSupplicant *exec.Cmd
mutexWpaSupplicant *sync.Mutex
CmdHostapd *exec.Cmd
mutexHostapd *sync.Mutex
IfaceName string
PathWpaSupplicantConf string
PathHostapdConf string
LoggerHostapd *util.TeeLogger
LoggerWpaSupplicant *util.TeeLogger
OutMonitorWpaSupplicant *wpaSupplicantOutMonitor
func wifiCheckExternalBinaries() error {
if !binaryAvailable("wpa_supplicant") {
return errors.New("wpa_supplicant seems to be missing, please install it")
}
// to create wpa_supplicant.conf
if !binaryAvailable("wpa_passphrase") {
return errors.New("wpa_passphrase seems to be missing, please install it")
}
if !binaryAvailable("hostapd") {
return errors.New("hostapd seems to be missing, please install it")
}
// for wifiScan
if !binaryAvailable("iw") {
return errors.New("The tool 'iw' seems to be missing, please install it")
}
return nil
}
type WiFiService struct {
State *pb.WiFi2State
Settings *pb.WiFi2Settings
mutexSettings *sync.Mutex // Lock settings on change
CmdWpaSupplicant *exec.Cmd //Manages wpa-supplicant process
mutexWpaSupplicant *sync.Mutex //mutex for wpa-supplicant proc
CmdHostapd *exec.Cmd //Manages hostapd process
mutexHostapd *sync.Mutex //hostapd proc lock
IfaceName string //Name of WiFi interface
PathWpaSupplicantConf string // path to config file for wpa-supplicant
PathHostapdConf string // path to config file for hostapd
LoggerHostapd *util.TeeLogger //logger for hostapd
LoggerWpaSupplicant *util.TeeLogger //logger for WPA supplicant
OutMonitorWpaSupplicant *wpaSupplicantOutMonitor //Monitors wpa_supplicant output and sets signals where needed
}
func (wSvc *WiFiService) StartHostapd() (err error) {
log.Printf("Starting hostapd for interface '%s'...\n", wSvc.IfaceName)
wSvc.mutexHostapd.Lock()
defer wSvc.mutexHostapd.Unlock()
//stop hostapd if already running
if wSvc.CmdHostapd != nil {
// avoid deadlock
wSvc.mutexHostapd.Unlock()
wSvc.StopHostapd()
wSvc.mutexHostapd.Lock()
}
wSvc.CmdHostapd = exec.Command("/usr/sbin/hostapd", wSvc.PathHostapdConf)
wSvc.CmdHostapd.Stdout = wSvc.LoggerHostapd.LogWriter
wSvc.CmdHostapd.Stderr = wSvc.LoggerHostapd.LogWriter
err = wSvc.CmdHostapd.Start()
if err != nil {
wSvc.CmdHostapd.Wait()
return errors.New(fmt.Sprintf("Error starting hostapd '%v'", err))
}
log.Printf("... hostapd for interface '%s' started\n", wSvc.IfaceName)
return nil
}
func (wSvc *WiFiService) StopHostapd() (err error) {
eSuccess := fmt.Sprintf("... hostapd for interface '%s' stopped", wSvc.IfaceName)
eCantStop := fmt.Sprintf("... couldn't terminate hostapd for interface '%s'", wSvc.IfaceName)
wSvc.mutexHostapd.Lock()
defer wSvc.mutexHostapd.Unlock()
if wSvc.CmdHostapd == nil {
log.Printf("... hostapd for interface '%s' isn't running, no need to stop it\n", wSvc.IfaceName)
return nil
}
wSvc.CmdHostapd.Process.Signal(syscall.SIGTERM)
wSvc.CmdHostapd.Wait()
if !wSvc.CmdHostapd.ProcessState.Exited() {
log.Printf("... hostapd didn't react on SIGTERM for interface '%s', trying SIGKILL\n", wSvc.IfaceName)
wSvc.CmdHostapd.Process.Kill()
time.Sleep(500 * time.Millisecond)
if wSvc.CmdHostapd.ProcessState.Exited() {
wSvc.CmdHostapd = nil
log.Println(eSuccess)
return nil
} else {
log.Println(eCantStop)
return errors.New(eCantStop)
}
}
wSvc.CmdHostapd = nil
log.Println(eSuccess)
return nil
}
func (wSvc *WiFiService) StopWpaSupplicant() (err error) {
eSuccess := fmt.Sprintf("... wpa_supplicant for interface '%s' stopped", wSvc.IfaceName)
eCantStop := fmt.Sprintf("... couldn't terminate wpa_supplicant for interface '%s'", wSvc.IfaceName)
log.Printf("... stop running wpa_supplicant processes for interface '%s'\n", wSvc.IfaceName)
wSvc.mutexWpaSupplicant.Lock()
defer wSvc.mutexWpaSupplicant.Unlock()
if wSvc.CmdWpaSupplicant == nil {
log.Printf("... wpa_supplicant for interface '%s' wasn't running, no need to stop it\n", wSvc.IfaceName)
return nil
}
log.Printf("... sending SIGTERM for wpa_supplicant on interface '%s' with PID\n", wSvc.IfaceName, wSvc.CmdWpaSupplicant.Process.Pid)
wSvc.CmdWpaSupplicant.Process.Signal(syscall.SIGTERM)
wSvc.CmdWpaSupplicant.Wait()
if !wSvc.CmdWpaSupplicant.ProcessState.Exited() {
log.Printf("... wpa_supplicant didn't react on SIGTERM for interface '%s', trying SIGKILL\n", wSvc.IfaceName)
wSvc.CmdWpaSupplicant.Process.Kill()
time.Sleep(500 * time.Millisecond)
if wSvc.CmdWpaSupplicant.ProcessState.Exited() {
wSvc.CmdWpaSupplicant = nil
log.Println(eSuccess)
return nil
} else {
log.Println(eCantStop)
return errors.New(eCantStop)
}
}
wSvc.CmdWpaSupplicant = nil
log.Println(eSuccess)
return nil
}
func (wSvc *WiFiService) StartWpaSupplicant(timeout time.Duration) (err error) {
log.Printf("Starting wpa_supplicant for interface '%s'...\n", wSvc.IfaceName)
wSvc.mutexWpaSupplicant.Lock()
defer wSvc.mutexWpaSupplicant.Unlock()
//stop wpa_supplicant if already running
if wSvc.CmdWpaSupplicant != nil {
// avoid dead lock
wSvc.mutexWpaSupplicant.Unlock()
wSvc.StopWpaSupplicant()
wSvc.mutexWpaSupplicant.Lock()
}
//we monitor output of wpa_supplicant till we are connected, fail due to wrong PSK or timeout is reached
//Note: PID file creation doesn't work when not started as daemon, so we do it manually, later on
wSvc.CmdWpaSupplicant = exec.Command("/sbin/wpa_supplicant", "-c", wSvc.PathWpaSupplicantConf, "-i", wSvc.IfaceName)
wSvc.CmdWpaSupplicant.Stdout = wSvc.LoggerWpaSupplicant.LogWriter
err = wSvc.CmdWpaSupplicant.Start()
if err != nil {
return err
}
//wait for result in output
connected, errcon := wSvc.OutMonitorWpaSupplicant.WaitConnectResultOnce(timeout)
if errcon != nil {
log.Printf("... wpa_supplicant reached timeout of '%v' without beeing able to connect to given network\n", timeout)
log.Println("... killing wpa_supplicant")
// avoid dead lock
wSvc.mutexWpaSupplicant.Unlock()
wSvc.StopWpaSupplicant()
wSvc.mutexWpaSupplicant.Lock()
return errors.New("TIMEOUT REACHED")
}
if connected {
//We could return success and keep wpa_supplicant running
log.Println("... connected to given WiFi network, wpa_supplicant running")
return nil
} else {
//we stop wpa_supplicant and return err
log.Println("... seems the wrong PSK was provided for the given WiFi network, stopping wpa_supplicant ...")
//wifiStopWpaSupplicant(nameIface)
log.Println("... killing wpa_supplicant")
// avoid dead lock
wSvc.mutexWpaSupplicant.Unlock()
wSvc.StopWpaSupplicant()
wSvc.mutexWpaSupplicant.Lock()
return errors.New("Wrong PSK")
}
return nil
}
func (wSvc *WiFiService) GetState() pb.WiFi2State {
return *wSvc.State
}
func MatchGivenBBSToScanResult(scanRes []BSS, targets []*pb.WiFi2BSSCfg) (matches []*pb.WiFi2BSSCfg) {
for _,bssCfgTarget := range targets {
for _,bssCfgScan := range scanRes {
if bssCfgScan.SSID == bssCfgTarget.SSID {
// SSID match, possible candidate
matches = append(matches, bssCfgTarget)
}
}
}
return
}
func (wSvc *WiFiService) runStaMode(newWifiSettings *pb.WiFi2Settings) (err error) {
if len(newWifiSettings.Client_BSSList) == 0 {
return errors.New("Error: WiFi mode set to station (STA) but no BSS configurations provided")
}
//scan for provided wifi
scanres, err := WifiScan(wSvc.IfaceName)
if err != nil {
return errors.New(fmt.Sprintf("Scanning for existing WiFi networks failed: %v", err))
}
matchingBssList := MatchGivenBBSToScanResult(scanres, newWifiSettings.Client_BSSList)
if len(matchingBssList) == 0 {
return errors.New(fmt.Sprintf("Non of the given SSIDs found during scan\n"))
}
// Create config for the remaining networks
confstr, err := wifiCreateWpaSupplicantConfStringList(matchingBssList)
if err != nil { return err }
// store config to file
log.Printf("Creating wpa_supplicant configuration file at '%s'\n", wSvc.PathWpaSupplicantConf)
err = ioutil.WriteFile(wSvc.PathWpaSupplicantConf, []byte(confstr), os.ModePerm)
if err != nil { return err }
//ToDo: proper error handling, in case connection not possible
err = wSvc.StartWpaSupplicant(WPA_SUPPLICANT_CONNECT_TIMEOUT)
if err != nil { return err }
wSvc.State.Bss.SSID = "unknown SSID"
wSvc.State.Channel = newWifiSettings.Channel
wSvc.State.Regulatory = newWifiSettings.Regulatory
wSvc.State.HideSsid = newWifiSettings.HideSsid
wSvc.State.WorkingMode = pb.WiFi2WorkingMode_STA
wSvc.State.Disabled = false
return nil
}
// ToDo: Output monitor for AP-ENABLED (same approach as for wpa_supplicant)
func (wSvc *WiFiService) runAPMode(newWifiSettings *pb.WiFi2Settings) (err error) {
//generate hostapd.conf (overwrite old one)
hostapdCreateConfigFile2(newWifiSettings, wSvc.PathHostapdConf)
//start hostapd
err = wSvc.StartHostapd()
if err != nil {
wSvc.State.WorkingMode = pb.WiFi2WorkingMode_UNKNOWN
return err
}
// update Connection wSvc
wSvc.State.Bss.SSID = newWifiSettings.Ap_BSS.SSID
wSvc.State.Channel = newWifiSettings.Channel
wSvc.State.Regulatory = newWifiSettings.Regulatory
wSvc.State.HideSsid = newWifiSettings.HideSsid
wSvc.State.WorkingMode = pb.WiFi2WorkingMode_AP
wSvc.State.Disabled = false
return nil
}
func (wSvc *WiFiService) DeploySettings(newWifiSettings *pb.WiFi2Settings) (wstate *pb.WiFi2State, err error) {
log.Println("Deploying new WiFi settings...")
log.Printf("Settings: %+v\n", newWifiSettings)
wSvc.mutexSettings.Lock()
defer wSvc.mutexSettings.Unlock()
// Reset wSvc to unknown, if something goes wrong, there's no wpa_supplicant or hostapd
wSvc.State.WorkingMode = pb.WiFi2WorkingMode_UNKNOWN
//ToDo: Dis/Enable nexmon if needed
//stop wpa_supplicant if needed
err = wSvc.StopWpaSupplicant()
if err != nil { return wSvc.State, err}
//kill hostapd in case it is still running
err = wSvc.StopHostapd()
if err != nil { return wSvc.State, err}
wSvc.State.Disabled = true
if !newWifiSettings.Disabled {
switch newWifiSettings.WorkingMode {
case pb.WiFi2WorkingMode_AP:
err = wSvc.runAPMode(newWifiSettings)
case pb.WiFi2WorkingMode_STA, pb.WiFi2WorkingMode_STA_FAILOVER_AP:
errSta := wSvc.runStaMode(newWifiSettings)
if errSta != nil {
//in failover mode, we try to enable AP first
if newWifiSettings.WorkingMode == pb.WiFi2WorkingMode_STA_FAILOVER_AP {
log.Println(errSta)
log.Printf("Trying to fail over to Access Point Mode...")
err = wSvc.runAPMode(newWifiSettings)
} else {
err = errSta
}
}
default:
// None allowed working mode, so we leave wSvc as UNKNOWN
err = errors.New("Unknown working mode")
}
}
if err == nil {
log.Printf("... WiFi settings deployed successfully\n")
} else {
log.Printf("... deploying WiFi settings failed: %s\n", err.Error())
}
// update settings (wSvc is updated by runAPMode/runStaMode)
wSvc.Settings = newWifiSettings
return wSvc.State, nil
}
func NewWifiService() (res *WiFiService) {
ifName := wifi_if_name
err := wifiCheckExternalBinaries()
if err != nil { panic(err) }
//Check interface existence
if exists,_ := CheckInterfaceExistence(ifName); !exists {
panic(errors.New(fmt.Sprintf("WiFi interface '%s' not present")))
}
res = &WiFiService{
mutexSettings: &sync.Mutex{},
CmdWpaSupplicant: nil,
mutexWpaSupplicant: &sync.Mutex{},
CmdHostapd: nil,
mutexHostapd: &sync.Mutex{},
IfaceName: ifName,
PathWpaSupplicantConf: fmt.Sprintf("/tmp/wpa_supplicant_%s.conf", ifName),
PathHostapdConf: fmt.Sprintf("/tmp/hostapd_%s.conf", ifName),
}
res.OutMonitorWpaSupplicant = NewWpaSupplicantOutMonitor()
res.LoggerHostapd = util.NewTeeLogger(true)
res.LoggerHostapd.SetPrefix("hostapd: ")
res.LoggerWpaSupplicant = util.NewTeeLogger(true)
res.LoggerWpaSupplicant.SetPrefix("wpa_supplicant: ")
res.LoggerWpaSupplicant.AddOutput(res.OutMonitorWpaSupplicant) // add watcher too tee'ed output writers
// Initial settings and state on service start
res.Settings = &pb.WiFi2Settings{
Disabled: false,
WorkingMode: pb.WiFi2WorkingMode_AP,
Client_BSSList: []*pb.WiFi2BSSCfg{},
Ap_BSS: &pb.WiFi2BSSCfg{},
}
res.State = &pb.WiFi2State{
Disabled: true,
WorkingMode: pb.WiFi2WorkingMode_UNKNOWN,
Bss: &pb.WiFi2BSSCfg{},
}
return res
}
type wpaSupplicantOutMonitor struct {
resultReceived *util.Signal
@ -108,422 +449,26 @@ func NewWpaSupplicantOutMonitor() *wpaSupplicantOutMonitor {
}
}
func NewWifiState(startupSettings *pb.WiFiSettings, ifName string) (res *WifiState) {
if !binaryAvailable("wpa_supplicant") {
panic("wpa_supplicant seems to be missing, please install it")
}
// to create wpa_supplicant.conf
if !binaryAvailable("wpa_passphrase") {
panic("wpa_passphrase seems to be missing, please install it")
}
if !binaryAvailable("hostapd") {
panic("hostapd seems to be missing, please install it")
}
// for wifiScan
if !binaryAvailable("iw") {
panic("The tool 'iw' seems to be missing, please install it")
}
res = &WifiState{
mutexSettings: &sync.Mutex{},
IfaceName: ifName,
Settings: startupSettings,
CmdWpaSupplicant: nil,
mutexWpaSupplicant: &sync.Mutex{},
CmdHostapd: nil,
mutexHostapd: &sync.Mutex{},
PathWpaSupplicantConf: fmt.Sprintf("/tmp/wpa_supplicant_%s.conf", ifName),
PathHostapdConf: fmt.Sprintf("/tmp/hostapd_%s.conf", ifName),
}
type WiFiAuthMode int
res.OutMonitorWpaSupplicant = NewWpaSupplicantOutMonitor()
res.LoggerHostapd = util.NewTeeLogger(true)
res.LoggerHostapd.SetPrefix("hostapd: ")
res.LoggerWpaSupplicant = util.NewTeeLogger(true)
res.LoggerWpaSupplicant.SetPrefix("wpa_supplicant: ")
res.LoggerWpaSupplicant.AddOutput(res.OutMonitorWpaSupplicant) // add watcher too tee'ed output writers
return
}
func (wifiState *WifiState) StartHostapd() (err error) {
log.Printf("Starting hostapd for interface '%s'...\n", wifiState.IfaceName)
wifiState.mutexHostapd.Lock()
defer wifiState.mutexHostapd.Unlock()
//check if interface is valid
if_exists, _ := CheckInterfaceExistence(wifiState.IfaceName)
if !if_exists {
return errors.New(fmt.Sprintf("The given interface '%s' doesn't exist", wifiState.IfaceName))
}
//stop hostapd if already running
if wifiState.CmdHostapd != nil {
// avoid deadlock
wifiState.mutexHostapd.Unlock()
wifiState.StopHostapd()
wifiState.mutexHostapd.Lock()
}
//We use the run command and allow hostapd to daemonize
//wifiState.CmdHostapd = exec.Command("/usr/sbin/hostapd", "-f", logFileHostapd(wifiState.IfaceName), wifiState.PathHostapdConf)
wifiState.CmdHostapd = exec.Command("/usr/sbin/hostapd", wifiState.PathHostapdConf)
wifiState.CmdHostapd.Stdout = wifiState.LoggerHostapd.LogWriter
wifiState.CmdHostapd.Stderr = wifiState.LoggerHostapd.LogWriter
err = wifiState.CmdHostapd.Start()
if err != nil {
//bytes, _ := wifiState.CmdHostapd.CombinedOutput()
//println(string(bytes))
wifiState.CmdHostapd.Wait()
return errors.New(fmt.Sprintf("Error starting hostapd '%v'", err))
}
log.Printf("... hostapd for interface '%s' started\n", wifiState.IfaceName)
return nil
}
func (wifiState *WifiState) StopHostapd() (err error) {
eSuccess := fmt.Sprintf("... hostapd for interface '%s' stopped", wifiState.IfaceName)
eCantStop := fmt.Sprintf("... couldn't terminate hostapd for interface '%s'", wifiState.IfaceName)
wifiState.mutexHostapd.Lock()
defer wifiState.mutexHostapd.Unlock()
if wifiState.CmdHostapd == nil {
log.Printf("... hostapd for interface '%s' isn't running, no need to stop it\n", wifiState.IfaceName)
return nil
}
wifiState.CmdHostapd.Process.Signal(syscall.SIGTERM)
wifiState.CmdHostapd.Wait()
if !wifiState.CmdHostapd.ProcessState.Exited() {
log.Printf("... hostapd didn't react on SIGTERM for interface '%s', trying SIGKILL\n", wifiState.IfaceName)
wifiState.CmdHostapd.Process.Kill()
time.Sleep(500 * time.Millisecond)
if wifiState.CmdHostapd.ProcessState.Exited() {
wifiState.CmdHostapd = nil
log.Println(eSuccess)
return nil
} else {
log.Println(eCantStop)
return errors.New(eCantStop)
}
}
wifiState.CmdHostapd = nil
log.Println(eSuccess)
return nil
}
func (wifiState *WifiState) StopWpaSupplicant() (err error) {
eSuccess := fmt.Sprintf("... wpa_supplicant for interface '%s' stopped", wifiState.IfaceName)
eCantStop := fmt.Sprintf("... couldn't terminate wpa_supplicant for interface '%s'", wifiState.IfaceName)
log.Printf("... stop running wpa_supplicant processes for interface '%s'\n", wifiState.IfaceName)
wifiState.mutexWpaSupplicant.Lock()
defer wifiState.mutexWpaSupplicant.Unlock()
if wifiState.CmdWpaSupplicant == nil {
log.Printf("... wpa_supplicant for interface '%s' wasn't running, no need to stop it\n", wifiState.IfaceName)
return nil
}
log.Printf("... sending SIGTERM for wpa_supplicant on interface '%s' with PID\n", wifiState.IfaceName, wifiState.CmdWpaSupplicant.Process.Pid)
wifiState.CmdWpaSupplicant.Process.Signal(syscall.SIGTERM)
wifiState.CmdWpaSupplicant.Wait()
if !wifiState.CmdWpaSupplicant.ProcessState.Exited() {
log.Printf("... wpa_supplicant didn't react on SIGTERM for interface '%s', trying SIGKILL\n", wifiState.IfaceName)
wifiState.CmdWpaSupplicant.Process.Kill()
time.Sleep(500 * time.Millisecond)
if wifiState.CmdWpaSupplicant.ProcessState.Exited() {
wifiState.CmdWpaSupplicant = nil
log.Println(eSuccess)
return nil
} else {
log.Println(eCantStop)
return errors.New(eCantStop)
}
}
wifiState.CmdWpaSupplicant = nil
log.Println(eSuccess)
return nil
}
func (wifiState *WifiState) StartWpaSupplicant(timeout time.Duration) (err error) {
log.Printf("Starting wpa_supplicant for interface '%s'...\n", wifiState.IfaceName)
wifiState.mutexWpaSupplicant.Lock()
defer wifiState.mutexWpaSupplicant.Unlock()
//check if interface is valid
if_exists, _ := CheckInterfaceExistence(wifiState.IfaceName)
if !if_exists {
return errors.New(fmt.Sprintf("The given interface '%s' doesn't exist", wifiState.IfaceName))
}
//stop wpa_supplicant if already running
if wifiState.CmdWpaSupplicant != nil {
// avoid dead lock
wifiState.mutexWpaSupplicant.Unlock()
wifiState.StopWpaSupplicant()
wifiState.mutexWpaSupplicant.Lock()
}
//we monitor output of wpa_supplicant till we are connected, fail due to wrong PSK or timeout is reached
//Note: PID file creation doesn't work when not started as daemon, so we do it manually, later on
wifiState.CmdWpaSupplicant = exec.Command("/sbin/wpa_supplicant", "-c", wifiState.PathWpaSupplicantConf, "-i", wifiState.IfaceName)
wifiState.CmdWpaSupplicant.Stdout = wifiState.LoggerWpaSupplicant.LogWriter
err = wifiState.CmdWpaSupplicant.Start()
if err != nil {
return err
}
//wait for result in output
connected, errcon := wifiState.OutMonitorWpaSupplicant.WaitConnectResultOnce(timeout)
if errcon != nil {
log.Printf("... wpa_supplicant reached timeout of '%v' without beeing able to connect to given network\n", timeout)
log.Println("... killing wpa_supplicant")
// avoid dead lock
wifiState.mutexWpaSupplicant.Unlock()
wifiState.StopWpaSupplicant()
wifiState.mutexWpaSupplicant.Lock()
return errors.New("TIMEOUT REACHED")
}
if connected {
//We could return success and keep wpa_supplicant running
log.Println("... connected to given WiFi network, wpa_supplicant running")
return nil
} else {
//we stop wpa_supplicant and return err
log.Println("... seems the wrong PSK was provided for the given WiFi network, stopping wpa_supplicant ...")
//wifiStopWpaSupplicant(nameIface)
log.Println("... killing wpa_supplicant")
// avoid dead lock
wifiState.mutexWpaSupplicant.Unlock()
wifiState.StopWpaSupplicant()
wifiState.mutexWpaSupplicant.Lock()
return errors.New("Wrong PSK")
}
return nil
}
const (
WiFiAuthMode_OPEN WiFiAuthMode = iota
//WiFiAuthMode_WEP
WiFiAuthMode_WPA_PSK
WiFiAuthMode_WPA2_PSK
WiFiAuthMode_UNSUPPORTED
)
type BSS struct {
SSID string
BSSID net.HardwareAddr
Frequency int
BeaconInterval time.Duration //carefull, on IE level beacon interval isn't meassured in milliseconds
BeaconInterval time.Duration //carefull, on IE level beacon interval isn't measured in milliseconds
AuthMode WiFiAuthMode
Signal float32 //Signal strength in dBm
}
func (state WifiState) GetDeployWifiSettings() (ws *pb.WiFiSettings, err error) {
return state.Settings, nil
}
func (state *WifiState) DeployWifiSettings(newWifiSettings *pb.WiFiSettings) (err error) {
log.Printf("Trying to deploy WiFi settings:\n%v\n", newWifiSettings)
ifName := wifi_if_name
state.mutexSettings.Lock()
defer state.mutexSettings.Unlock()
//Get Interface
iface, err := net.InterfaceByName(ifName)
if err != nil {
return errors.New(fmt.Sprintf("No WiFi interface present: %v\n", err))
}
firmwareChange := false
if newWifiSettings.DisableNexmon {
//load legacy driver + firmware
if wifiIsNexmonLoaded() {
err = wifiLoadLegacy()
if err != nil {
return
}
firmwareChange = true
}
} else {
//load nexmon driver + firmware
if !wifiIsNexmonLoaded() {
err = wifiLoadNexmon()
if err != nil {
return
}
firmwareChange = true
}
}
if firmwareChange {
ReInitNetworkInterface(ifName)
}
linkStateChange := false
currentlyEnabled, errstate := netlink.NetworkLinkGetStateUp(iface)
if errstate != nil {
linkStateChange = true
} // current link state couldn't be retireved, regard as changed
if currentlyEnabled == newWifiSettings.Disabled {
linkStateChange = true
} //Is disabled and should be enabled, or the other way around
if linkStateChange || firmwareChange { // Enable/Disable if only if needed
// ToDo: the new interface state isn't reflected to respective ethernet settings
if newWifiSettings.Disabled {
log.Printf("Setting WiFi interface %s to DOWN\n", iface.Name)
err = netlink.NetworkLinkDown(iface)
} else {
log.Printf("Setting WiFi interface %s to UP\n", iface.Name)
err = netlink.NetworkLinkUp(iface)
}
}
//set proper regulatory dom
err = wifiSetReg(newWifiSettings.Reg)
if err != nil {
log.Printf("Error setting WiFi regulatory domain '%s': %v\n", newWifiSettings.Reg, err) //we don't abort on error here
}
//stop wpa_supplicant if needed
state.StopWpaSupplicant()
//kill hostapd in case it is still running
err = state.StopHostapd()
if err != nil {
return err // ToDo: returning at this point is a bit harsh
}
switch newWifiSettings.Mode {
case pb.WiFiSettings_AP:
err = state.runAPMode(newWifiSettings)
if err != nil {
return err
}
case pb.WiFiSettings_STA, pb.WiFiSettings_STA_FAILOVER_AP:
if newWifiSettings.BssCfgClient == nil {
return state.apFailoverOrError(
newWifiSettings,
errors.New("Error: WiFi mode set to station (STA) but no BSS configuration for target WiFi provided"),
)
}
if len(newWifiSettings.BssCfgClient.SSID) == 0 {
return state.apFailoverOrError(
newWifiSettings,
errors.New("Error: WiFi mode set to station (STA) but no SSID provided to identify BSS to join"),
)
}
//scan for provided wifi
scanres, err := WifiScan(ifName)
if err != nil {
return state.apFailoverOrError(
newWifiSettings,
errors.New(fmt.Sprintf("Scanning for existing WiFi networks failed: %v", err)),
)
}
var matchingBss *BSS = nil
for _, bss := range scanres {
if bss.SSID == newWifiSettings.BssCfgClient.SSID {
matchingBss = &bss
break
}
}
if matchingBss == nil {
return state.apFailoverOrError(
newWifiSettings,
errors.New(fmt.Sprintf("SSID not found during scan: '%s'", newWifiSettings.BssCfgClient.SSID)),
)
}
if len(newWifiSettings.BssCfgClient.PSK) == 0 && matchingBss.AuthMode != WiFiAuthMode_OPEN {
//seems we try to connect an OPEN AUTHENTICATION network, but the existing BSS isn't OPEN AUTH
return state.apFailoverOrError(
newWifiSettings,
errors.New(fmt.Sprintf("WiFi SSID '%s' found during scan, but authentication mode isn't OPEN and no PSK was provided", newWifiSettings.BssCfgClient.SSID)),
)
} else {
err = WifiCreateWpaSupplicantConfigFile(newWifiSettings.BssCfgClient.SSID, newWifiSettings.BssCfgClient.PSK, state.PathWpaSupplicantConf)
if err != nil {
return state.apFailoverOrError(
newWifiSettings,
err,
)
}
//ToDo: proper error handling, in case connection not possible
err = state.StartWpaSupplicant(WPA_SUPPLICANT_CONNECT_TIMEOUT)
if err != nil {
return state.apFailoverOrError(
newWifiSettings,
err,
)
}
}
}
log.Printf("... WiFi settings deployed successfully, checking for stored interface configuration...\n")
// store new state
state.Settings = newWifiSettings
return nil
}
func (state *WifiState) runAPMode(newWifiSettings *pb.WiFiSettings) (err error) {
//generate hostapd.conf (overwrite old one)
hostapdCreateConfigFile(newWifiSettings, state.PathHostapdConf)
//start hostapd
return state.StartHostapd()
}
func (state *WifiState) apFailoverOrError(newWifiSettings *pb.WiFiSettings, givenErr error) (err error) {
if newWifiSettings.Mode == pb.WiFiSettings_STA_FAILOVER_AP {
log.Println(givenErr)
log.Printf("Trying to fail over to Access Point Mode...")
return state.runAPMode(newWifiSettings)
} else {
return givenErr
}
}
//check if nexmon driver + firmware is active is loaded
func wifiIsNexmonLoaded() bool {
return true
}
func wifiLoadNexmon() error {
log.Println("Loading nexmon WiFi firmware")
return nil
}
func wifiLoadLegacy() error {
log.Println("Loading leagcy WiFi firmware")
return nil
}
func wifiSetReg(reg string) (err error) {
if len(reg) == 0 {
reg = "US" //default
log.Printf("No ISO/IEC 3166-1 alpha2 regulatory domain provided, defaulting to '%s'\n", reg)
}
reg = strings.ToUpper(reg)
proc := exec.Command("/sbin/iw", "reg", "set", reg)
err = proc.Run()
if err != nil {
return err
}
log.Printf("Notified kernel to use ISO/IEC 3166-1 alpha2 regulatory domain '%s'\n", reg)
return nil
}
func WifiScan(ifName string) (result []BSS, err error) {
proc := exec.Command("/sbin/iw", ifName, "scan")
res, err := proc.CombinedOutput()
@ -536,18 +481,11 @@ func WifiScan(ifName string) (result []BSS, err error) {
return
}
func WifiCreateWpaSupplicantConfigFile(ssid string, psk string, filename string) (err error) {
log.Printf("Creating wpa_suuplicant configuration file at '%s'\n", filename)
fileContent, err := wifiCreateWpaSupplicantConfString(ssid, psk)
if err != nil {
return
}
err = ioutil.WriteFile(filename, []byte(fileContent), os.ModePerm)
return
}
func wifiCreateWpaSupplicantConfString(ssid string, psk string) (config string, err error) {
// if a PSK is provided, we assume it is needed, otherwise we assum OPEN AUTHENTICATION
func wifiCreateWpaSupplicantConfStringList(bsslist []*pb.WiFi2BSSCfg) (config string, err error) {
// if a PSK is provided, we assume it is needed, otherwise we assume OPEN AUTHENTICATION
for _,bss := range bsslist {
ssid := bss.SSID
psk := bss.PSK
if len(psk) > 0 {
fmt.Println("Connecting WiFi with PSK")
proc := exec.Command("/usr/bin/wpa_passphrase", ssid, psk)
@ -556,14 +494,17 @@ func wifiCreateWpaSupplicantConfString(ssid string, psk string) (config string,
if err != nil {
return "", errors.New(fmt.Sprintf("Error craeting wpa_supplicant.conf for SSID '%s' with PSK '%s': %s", ssid, psk, string(cres)))
}
config = string(cres)
config += string(cres)
} else {
fmt.Println("Connecting WiFi with OPEN AUTH")
config = fmt.Sprintf(
config += fmt.Sprintf(
`network={
ssid="%s"
key_mgmt=NONE
}`, ssid)
}
`, ssid)
}
}
@ -572,12 +513,13 @@ func wifiCreateWpaSupplicantConfString(ssid string, psk string) (config string,
return
}
func wifiCreateHostapdConfString(ws *pb.WiFiSettings) (config string, err error) {
if ws.Mode != pb.WiFiSettings_STA_FAILOVER_AP && ws.Mode != pb.WiFiSettings_AP {
return "", errors.New("WiFiSettings don't use an AP")
func wifiCreateHostapdConfString2(ws *pb.WiFi2Settings) (config string, err error) {
if ws.WorkingMode != pb.WiFi2WorkingMode_AP && ws.WorkingMode != pb.WiFi2WorkingMode_STA_FAILOVER_AP {
return "", errors.New("Couldn't create hostapd configuration, the settings don't include an AP")
}
if ws.BssCfgAP == nil {
if ws.Ap_BSS == nil {
return "", errors.New("WiFiSettings don't contain a BSS configuration for an AP")
}
@ -590,22 +532,22 @@ func wifiCreateHostapdConfString(ws *pb.WiFiSettings) (config string, err error)
config += fmt.Sprintf("ht_capab=[HT40][SHORT-GI-20][DSSS_CCK-40]\n") // 40MHz channels with 20ns guard interval
config += fmt.Sprintf("macaddr_acl=0\n") //Accept all MAC addresses
config += fmt.Sprintf("ssid=%s\n", ws.BssCfgAP.SSID)
config += fmt.Sprintf("channel=%d\n", ws.ApChannel)
config += fmt.Sprintf("ssid=%s\n", ws.Ap_BSS.SSID)
config += fmt.Sprintf("channel=%d\n", ws.Channel)
if ws.AuthMode == pb.WiFiSettings_WPA2_PSK {
if ws.AuthMode == pb.WiFi2AuthMode_WPA2_PSK {
config += fmt.Sprintf("auth_algs=1\n") //Use WPA authentication
config += fmt.Sprintf("wpa=2\n") //Use WPA2
//ToDo: check if PSK could be provided encrypted
config += fmt.Sprintf("wpa_key_mgmt=WPA-PSK\n") //Use a pre-shared key
config += fmt.Sprintf("wpa_passphrase=%s\n", ws.BssCfgAP.PSK) //Set PSK
config += fmt.Sprintf("wpa_passphrase=%s\n", ws.Ap_BSS.PSK) //Set PSK
config += fmt.Sprintf("rsn_pairwise=CCMP\n") //Use Use AES, instead of TKIP
} else {
config += fmt.Sprintf("auth_algs=3\n") //Both, open and shared auth
}
if ws.ApHideSsid {
if ws.HideSsid {
config += fmt.Sprintf("ignore_broadcast_ssid=2\n") //Require clients to know the SSID
} else {
config += fmt.Sprintf("ignore_broadcast_ssid=0\n") //Send beacons + probes
@ -614,9 +556,9 @@ func wifiCreateHostapdConfString(ws *pb.WiFiSettings) (config string, err error)
return
}
func hostapdCreateConfigFile(s *pb.WiFiSettings, filename string) (err error) {
func hostapdCreateConfigFile2(s *pb.WiFi2Settings, filename string) (err error) {
log.Printf("Creating hostapd configuration file at '%s'\n", filename)
fileContent, err := wifiCreateHostapdConfString(s)
fileContent, err := wifiCreateHostapdConfString2(s)
if err != nil {
return
}

View File

@ -118,6 +118,7 @@ func GetDefaultGadgetSettings() (res pb.GadgetSettings) {
return res
}
/*
func GetDefaultWiFiSettings() (res *pb.WiFiSettings) {
res = &pb.WiFiSettings{
Mode: pb.WiFiSettings_AP,
@ -135,3 +136,4 @@ func GetDefaultWiFiSettings() (res *pb.WiFiSettings) {
}
return
}
*/

View File

@ -1,3 +1,5 @@
// +build linux
package service
import (
@ -28,20 +30,34 @@ var (
type server struct {}
func (s *server) DeployWiFiSettings2(ctx context.Context, wset *pb.WiFi2Settings) (wstate *pb.WiFi2State, err error) {
return ServiceState.WifiSvc.DeploySettings(wset)
}
func (s *server) GetWiFiState2(ctx context.Context, empty *pb.Empty) (wstate *pb.WiFi2State, err error) {
st := ServiceState.WifiSvc.GetState()
return &st, nil
}
func (s *server) ListenWiFiStateChanges2(ctx context.Context, empty *pb.Empty) (wstate *pb.WiFi2State, err error) {
panic("implement me")
}
/*
func (s *server) GetDeployedWifiSettings(ctx context.Context, req *pb.Empty) (resp *pb.WiFiSettings, err error) {
return ServiceState.Wifi.GetDeployWifiSettings()
}
func (s *server) DeployWifiSettings(ctx context.Context, ws *pb.WiFiSettings) (empty *pb.Empty, err error) {
func (s *server) DeployWifiSettings(ctx context.Context, ws *pb.WiFiSettings) (wifiConState *pb.WiFiConnectionState, err error) {
log.Printf("Trying to deploy WiFi settings %v", ws)
empty = &pb.Empty{}
err = ServiceState.Wifi.DeployWifiSettings(ws)
if err != nil {
log.Printf("Error deploying WiFi settings settings %v", err)
}
return
return ServiceState.Wifi.ConState, err
}
*/
func (s *server) GetDeployedEthernetInterfaceSettings(ctx context.Context, req *pb.StringMessage) (resp *pb.EthernetInterfaceSettings, err error) {
if settings,exist := ServiceState.StoredNetworkSetting[req.Msg]; exist && settings.SettingsInUse {

View File

@ -12,7 +12,8 @@ type GlobalServiceState struct {
Led *LedState
HidDevPath map[string]string //stores device path for HID devices
StoredNetworkSetting map[string]*pb.EthernetInterfaceSettings
Wifi *WifiState
// Wifi *WifiState
WifiSvc *WiFiService
}
func InitGlobalServiceState() (err error) {
@ -40,7 +41,9 @@ func InitGlobalServiceState() (err error) {
IpAddress4: "172.24.0.1",
Netmask4: "255.255.255.0",
}
state.Wifi = NewWifiState(GetDefaultWiFiSettings(), wifi_if_name)
// state.Wifi = NewWifiState(GetDefaultWiFiSettings(), wifi_if_name)
state.WifiSvc = NewWifiService()
state.HidDevPath = make(map[string]string) //should be initialized BEFORE UsbGadgetManager uses it
state.EvMgr = NewEventManager(20)
@ -53,7 +56,6 @@ func InitGlobalServiceState() (err error) {
return nil
}
func (state *GlobalServiceState) StartService() {
state.EvMgr.Start()
}

View File

@ -41,10 +41,10 @@ func InitComponentsWiFi() {
Value int `js:"value"`
}{Object:O()}
mode.Value = val
switch pb.WiFiSettings_APAuthMode(val) {
case pb.WiFiSettings_WPA2_PSK:
switch pb.WiFi2AuthMode(val) {
case pb.WiFi2AuthMode_WPA2_PSK:
mode.Label = "WPA2"
case pb.WiFiSettings_OPEN:
case pb.WiFi2AuthMode_OPEN:
mode.Label = "Open"
default:
mode.Label = "Unknown"
@ -55,27 +55,30 @@ func InitComponentsWiFi() {
}),
hvue.Computed("wifiModes", func(vm *hvue.VM) interface{} {
modes := js.Global.Get("Array").New()
for val,_ := range pb.WiFiSettings_Mode_name {
for val,_ := range pb.WiFi2WorkingMode_name {
mode := struct {
*js.Object
Label string `js:"label"`
Value int `js:"value"`
}{Object:O()}
mode.Value = val
switch pb.WiFiSettings_Mode(val) {
case pb.WiFiSettings_AP:
switch pb.WiFi2WorkingMode(val) {
case pb.WiFi2WorkingMode_AP:
mode.Label = "Access Point (AP)"
case pb.WiFiSettings_STA:
case pb.WiFi2WorkingMode_STA:
mode.Label = "Station (Client)"
case pb.WiFiSettings_STA_FAILOVER_AP:
case pb.WiFi2WorkingMode_STA_FAILOVER_AP:
mode.Label = "Client with Failover to AP"
default:
mode.Label = "Unknown"
continue
}
modes.Call("push", mode)
}
return modes
}),
hvue.Computed("mode_ap", func(vm *hvue.VM) interface{} {return pb.WiFi2WorkingMode_AP}),
hvue.Computed("mode_sta", func(vm *hvue.VM) interface{} {return pb.WiFi2WorkingMode_STA_FAILOVER_AP}),
hvue.Computed("mode_failover", func(vm *hvue.VM) interface{} {return pb.WiFi2WorkingMode_STA_FAILOVER_AP}),
hvue.Method("reset",
func(vm *hvue.VM) {
vm.Get("$store").Call("dispatch", VUEX_ACTION_UPDATE_WIFI_SETTINGS_FROM_DEPLOYED)
@ -145,7 +148,7 @@ const templateWiFi = `
</q-card>
</div>
<div class="col-lg-4" v-if="settings.mode != 0">
<div class="col-lg-4" v-if="settings.mode == mode_sta || settings.mode == mode_failover">
<q-card class="full-height">
<q-card-title>
WiFi client settings
@ -172,7 +175,7 @@ const templateWiFi = `
</q-item-main>
</q-item>
<template v-if="settings.mode == 2">
<template v-if="settings.mode == mode_failover">
<q-item>
<q-item-main>
<q-alert type="warning">
@ -185,7 +188,7 @@ const templateWiFi = `
</q-card>
</div>
<div class="col-lg-4" v-if="settings.mode != 1">
<div class="col-lg-4" v-if="settings.mode == mode_ap || settings.mode == mode_failover">
<q-card class="full-height">
<q-card-title>
WiFi Access Point settings
@ -247,6 +250,17 @@ const templateWiFi = `
</q-list>
</q-card>
</div>
<div class="col-lg-12">
<q-card class="full-height">
<q-card-title>
<q-icon name="alarm" /><q-icon name="alarm" />
</q-card-title>
WiFiState {{ $store.state.wifiConnectionState }}
</q-card>
</div>
</div>
</q-page>

View File

@ -42,7 +42,6 @@ type VGadgetSettingsEthernet struct {
DevAddr string `js:"DevAddr"`
}
type VGadgetSettingsUMS struct {
*js.Object
Cdrom bool `js:"Cdrom"`
@ -121,7 +120,6 @@ func (jsGS *jsGadgetSettings) fromGS(gs *pb.GadgetSettings) {
}
}
func NewUSBGadgetSettings() *jsGadgetSettings {
gs := &jsGadgetSettings{
Object: O(),
@ -140,7 +138,6 @@ type jsEvent struct {
JSValues *js.Object `js:"values"`
}
func NewJsEventFromNative(event *pb.Event) (res *jsEvent) {
res = &jsEvent{Object: O()}
res.JSValues = js.Global.Get("Array").New()
@ -189,60 +186,86 @@ type jsHidEvent struct {
}
func (jsEv *jsEvent) toLogEvent() (res *jsLogEvent, err error) {
if jsEv.Type != common_web.EVT_LOG || len(jsEv.Values) != 4 { return nil,eNoLogEvent}
if jsEv.Type != common_web.EVT_LOG || len(jsEv.Values) != 4 {
return nil, eNoLogEvent
}
res = &jsLogEvent{Object: O()}
var ok bool
res.EvLogSource, ok = jsEv.Values[0].(string)
if !ok { return nil,eNoLogEvent }
if !ok {
return nil, eNoLogEvent
}
ll, ok := jsEv.Values[1].(int64)
if !ok { return nil,eNoLogEvent}
if !ok {
return nil, eNoLogEvent
}
res.EvLogLevel = int(ll)
res.EvLogMessage, ok = jsEv.Values[2].(string)
if !ok { return nil,eNoLogEvent}
if !ok {
return nil, eNoLogEvent
}
res.EvLogTime, ok = jsEv.Values[3].(string)
if !ok { return nil,eNoLogEvent}
if !ok {
return nil, eNoLogEvent
}
return res, nil
}
func (jsEv *jsEvent) toHidEvent() (res *jsHidEvent, err error) {
if jsEv.Type != common_web.EVT_HID || len(jsEv.Values) != 8 { return nil,eNoHidEvent}
if jsEv.Type != common_web.EVT_HID || len(jsEv.Values) != 8 {
return nil, eNoHidEvent
}
res = &jsHidEvent{Object: O()}
var ok bool
res.EvType, ok = jsEv.Values[0].(int64)
if !ok { return nil,eNoHidEvent }
if !ok {
return nil, eNoHidEvent
}
res.VMId, ok = jsEv.Values[1].(int64)
if !ok { return nil,eNoHidEvent}
if !ok {
return nil, eNoHidEvent
}
res.JobId, ok = jsEv.Values[2].(int64)
if !ok { return nil,eNoHidEvent}
if !ok {
return nil, eNoHidEvent
}
res.HasError, ok = jsEv.Values[3].(bool)
if !ok { return nil,eNoHidEvent}
if !ok {
return nil, eNoHidEvent
}
res.Result, ok = jsEv.Values[4].(string)
if !ok { return nil,eNoHidEvent}
if !ok {
return nil, eNoHidEvent
}
res.Error, ok = jsEv.Values[5].(string)
if !ok { return nil,eNoHidEvent}
if !ok {
return nil, eNoHidEvent
}
res.Message, ok = jsEv.Values[6].(string)
if !ok { return nil,eNoHidEvent}
if !ok {
return nil, eNoHidEvent
}
res.EvLogTime, ok = jsEv.Values[7].(string)
if !ok { return nil,eNoHidEvent}
if !ok {
return nil, eNoHidEvent
}
return res, nil
}
/* HIDJobList */
type jsHidJobState struct {
*js.Object
@ -324,7 +347,9 @@ func (jl *jsHidJobStateList) UpdateEntry(id, vmId int64, hasFailed, hasSucceeded
j.LastMessage = message
j.TextResult = textResult
j.LastUpdateTime = lastUpdateTime
if len(scriptSource) > 0 {j.ScriptSource = scriptSource}
if len(scriptSource) > 0 {
j.ScriptSource = scriptSource
}
//jl.Jobs.Set(strconv.Itoa(int(j.Id)), j) //jobs["j.ID"]=j <--Property addition/update can't be detected by Vue.js, see https://vuejs.org/v2/guide/list.html#Object-Change-Detection-Caveats
hvue.Set(jl.Jobs, key, j)
}
@ -335,20 +360,71 @@ func (jl *jsHidJobStateList) DeleteEntry(id int64) {
}
/* WiFi settings */
/*
type WiFiSettings struct {
Disabled bool
Reg string
Mode WiFiSettings_Mode
AuthMode WiFiSettings_APAuthMode
ApChannel uint32
BssCfgAP *BSSCfg
BssCfgClient *BSSCfg
ApHideSsid bool
DisableNexmon bool
type jsWiFiConnectionState struct {
*js.Object
Mode int `js:"mode"`
Reg string `js:"reg"`
Channel uint32 `js:"channel"`
SSID string `js:"SSID"`
Hidden bool `js:"hidden"`
Nexmon bool `js:"nexmon"`
Disabled bool `js:"disabled"`
}
func (target *jsWiFiConnectionState) fromGo(src *pb.WiFi2State) {
target.Mode = int(src.WorkingMode)
target.Reg = src.Regulatory
target.Channel = src.Channel
target.SSID = src.Bss.SSID
target.Hidden = src.HideSsid
target.Nexmon = src.Nexmon
target.Disabled = src.Disabled
return
}
func (src *jsWiFiConnectionState) toGo() (target *pb.WiFi2State) {
target = &pb.WiFi2State{
Regulatory: src.Reg,
Channel: src.Channel,
Bss: &pb.WiFi2BSSCfg{
SSID: src.SSID,
PSK: "",
},
HideSsid: src.Hidden,
Nexmon: src.Nexmon,
WorkingMode: pb.WiFi2WorkingMode(src.Mode),
Disabled: src.Disabled,
Name: "",
}
return
}
func (src jsWiFiConnectionState) ModeString() (strMode string) {
switch src.Mode {
case 1:
return "Access Point"
case 2:
return "Station"
default:
return "UNKNOWN"
}
}
func NewWiFiConnectionState() *jsWiFiConnectionState {
res := &jsWiFiConnectionState{Object: O()}
res.SSID = "Unknown SSID"
res.Channel = 0
res.Mode = 0
res.Hidden = false
res.Reg = "Unknown reg"
res.Nexmon = false
return res
}
*/
type jsWiFiSettings struct {
*js.Object
Disabled bool `js:"disabled"`
@ -412,7 +488,32 @@ func (src *jsWiFiSettings) toGo() (target *pb.WiFiSettings) {
SSID: src.AP_SSID,
PSK: src.AP_PSK,
},
}
return target
}
func (src *jsWiFiSettings) toGo2() (target *pb.WiFi2Settings) {
// assure undefined strings end up as empty strings
target = &pb.WiFi2Settings{
Name: "mainconfig",
Disabled: src.Disabled,
Regulatory: src.Reg,
WorkingMode: pb.WiFi2WorkingMode(src.Mode),
AuthMode: pb.WiFi2AuthMode(src.AuthMode),
Nexmon: !src.DisableNexmon,
Channel: uint32(src.Channel),
HideSsid: src.HideSsid,
Ap_BSS: &pb.WiFi2BSSCfg{
SSID: src.AP_SSID,
PSK: src.AP_PSK,
},
Client_BSSList: []*pb.WiFi2BSSCfg{
&pb.WiFi2BSSCfg{
SSID: src.STA_SSID,
PSK: src.STA_PSK,
},
},
}
return target
}
@ -489,7 +590,6 @@ func (iface *jsEthernetInterfaceSettings) CreateDhcpSettingsForInterface() {
settings.CallbackScript = ""
//ToDo: add missing fields
//Ranges array
settings.Ranges = js.Global.Get("Array").New()
settings.Options = js.Global.Get("Array").New()
@ -535,7 +635,6 @@ func (src *jsDHCPServerSettings) toGo() (target *pb.DHCPServerSettings) {
println("jsRanges", src.Ranges)
//Check if ranges are present
if src.Ranges != js.Undefined {
if numRanges := src.Ranges.Length(); numRanges > 0 {
@ -579,7 +678,6 @@ func (src *jsDHCPServerSettings) toGo() (target *pb.DHCPServerSettings) {
return target
}
func (settings *jsDHCPServerSettings) AddRange(dhcpRange *jsDHCPServerRange) {
if settings.Ranges == js.Undefined {
settings.Ranges = js.Global.Get("Array").New()
@ -588,7 +686,9 @@ func (settings *jsDHCPServerSettings) AddRange(dhcpRange *jsDHCPServerRange) {
}
func (settings *jsDHCPServerSettings) RemoveRange(dhcpRange *jsDHCPServerRange) {
if settings.Ranges == js.Undefined { return }
if settings.Ranges == js.Undefined {
return
}
//Check if in array
if idx := settings.Ranges.Call("indexOf", dhcpRange).Int(); idx > -1 {
@ -596,7 +696,6 @@ func (settings *jsDHCPServerSettings) RemoveRange(dhcpRange *jsDHCPServerRange)
}
}
func (settings *jsDHCPServerSettings) AddOption(dhcpOption *jsDHCPServerOption) {
if settings.Options == js.Undefined {
settings.Options = js.Global.Get("Array").New()
@ -604,9 +703,10 @@ func (settings *jsDHCPServerSettings) AddOption(dhcpOption *jsDHCPServerOption)
settings.Options.Call("push", dhcpOption)
}
func (settings *jsDHCPServerSettings) RemoveOption(dhcpOption *jsDHCPServerOption) {
if settings.Options == js.Undefined { return }
if settings.Options == js.Undefined {
return
}
//Check if in array
if idx := settings.Options.Call("indexOf", dhcpOption).Int(); idx > -1 {
@ -621,9 +721,10 @@ func (settings *jsDHCPServerSettings) AddStaticHost(dhcpStaticHost *jsDHCPServer
settings.StaticHosts.Call("push", dhcpStaticHost)
}
func (settings *jsDHCPServerSettings) RemoveStaticHost(dhcpStaticHost *jsDHCPServerStaticHost) {
if settings.StaticHosts == js.Undefined { return }
if settings.StaticHosts == js.Undefined {
return
}
//Check if in array
if idx := settings.StaticHosts.Call("indexOf", dhcpStaticHost).Int(); idx > -1 {
@ -631,7 +732,6 @@ func (settings *jsDHCPServerSettings) RemoveStaticHost(dhcpStaticHost *jsDHCPSer
}
}
func (target *jsDHCPServerSettings) fromGo(src *pb.DHCPServerSettings) {
target.ListenPort = int(src.ListenPort)
target.ListenInterface = src.ListenInterface
@ -678,7 +778,6 @@ func (target *jsDHCPServerRange) fromGo(src *pb.DHCPServerRange) {
target.LeaseTime = src.LeaseTime
}
type jsDHCPServerOption struct {
*js.Object
Option int `js:"option"`
@ -759,7 +858,6 @@ func (data *jsEventReceiver) handleHidEvent(hEv *jsHidEvent ) {
}
/* This method gets internalized and therefor the mutex won't be accessible*/
func (data *jsEventReceiver) HandleEvent(ev *pb.Event) {
go func() {

View File

@ -63,6 +63,7 @@ type GlobalState struct {
FailedConnectionAttempts int `js:"failedConnectionAttempts"`
InterfaceSettings *jsEthernetSettingsList `js:"InterfaceSettings"`
WiFiSettings *jsWiFiSettings `js:"wifiSettings"`
WiFiState *jsWiFiConnectionState `js:"wifiConnectionState"`
}
func createGlobalStateStruct() GlobalState {
@ -89,7 +90,7 @@ func createGlobalStateStruct() GlobalState {
panic("Couldn't retrieve WiFi settings")
}
state.WiFiSettings = wifiSettings
state.WiFiState = NewWiFiConnectionState()
return state
}
@ -128,16 +129,32 @@ func actionUpdateWifiSettingsFromDeployed(store *mvuex.Store, context *mvuex.Act
return
}
/*
func actionDeployWifiSettings(store *mvuex.Store, context *mvuex.ActionContext, state *GlobalState, settings *jsWiFiSettings) {
go func() {
println("Vuex dispatch deploy WiFi settings")
// convert to Go type
goSettings := settings.toGo()
err := RpcClient.DeployeWifiSettings(time.Second*3, goSettings)
wstate, err := RpcClient.DeployWifiSettings(time.Second*20, goSettings)
if err != nil {
Alert(err)
QuasarNotifyError("Error deploying WiFi Settings", err.Error(), QUASAR_NOTIFICATION_POSITION_BOTTOM)
}
state.WiFiState.fromGo(wstate)
}()
}
*/
func actionDeployWifiSettings(store *mvuex.Store, context *mvuex.ActionContext, state *GlobalState, settings *jsWiFiSettings) {
go func() {
println("Vuex dispatch deploy WiFi settings")
// convert to Go type
goSettings := settings.toGo2()
wstate, err := RpcClient.DeployWifiSettings2(time.Second*20, goSettings)
if err != nil {
QuasarNotifyError("Error deploying WiFi Settings", err.Error(), QUASAR_NOTIFICATION_POSITION_BOTTOM)
}
state.WiFiState.fromGo(wstate)
}()
}

View File

@ -39,15 +39,24 @@ func (rpc *Rpc) DeployedEthernetInterfaceSettings(timeout time.Duration, setting
return
}
func (rpc *Rpc) DeployeWifiSettings(timeout time.Duration, settings *pb.WiFiSettings) (err error) {
func (rpc *Rpc) DeployWifiSettings(timeout time.Duration, settings *pb.WiFiSettings) (state *pb.WiFiConnectionState, err error) {
// ToDo: The RPC call has to return an error in case deployment fails
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
_, err = rpc.Client.DeployWifiSettings(ctx, settings)
state, err = rpc.Client.DeployWifiSettings(ctx, settings)
return
}
func (rpc *Rpc) DeployWifiSettings2(timeout time.Duration, settings *pb.WiFi2Settings) (state *pb.WiFi2State, err error) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
state, err = rpc.Client.DeployWiFiSettings2(ctx, settings)
return
}
func (rpc *Rpc) GetDeployedWiFiSettings(timeout time.Duration) (settingsList *jsWiFiSettings, err error) {
/*
//ToDo: Only placeholder, replace with real "get deployed" RPC