blob: 870be429aaf434bda4f901e6566f694b5339a466 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package main
import (
"app/context"
"fidl/bindings"
"syscall/zx"
"syscall/zx/mxerror"
"garnet/public/lib/wlan/fidl/wlan_service"
"netstack/watcher"
"wlan/wlan"
"log"
"sync"
)
type Wlanstack struct {
cfg *wlan.Config
apCfg *wlan.APConfig
stubs []*bindings.Stub
mu sync.Mutex
client []*wlan.Client
}
func (ws *Wlanstack) Scan(sr wlan_service.ScanRequest) (res wlan_service.ScanResult, err error) {
cli := ws.getCurrentClient()
if cli == nil {
return wlan_service.ScanResult{
wlan_service.Error{
wlan_service.ErrCode_NotFound,
"No wlan interface found"},
nil,
}, nil
}
respC := make(chan *wlan.CommandResult, 1)
cli.PostCommand(wlan.CmdScan, &sr, respC)
resp := <-respC
if resp.Err != nil {
return wlan_service.ScanResult{
*resp.Err,
nil,
}, nil
}
waps, ok := resp.Resp.([]wlan.AP)
if !ok {
return wlan_service.ScanResult{
wlan_service.Error{
wlan_service.ErrCode_Internal,
"Internal error"},
nil,
}, nil
}
aps := []wlan_service.Ap{}
for _, wap := range waps {
bssid := make([]uint8, len(wap.BSSID))
copy(bssid, wap.BSSID[:])
// Currently we indicate the AP is secure if it supports RSN.
// TODO: Check if AP supports other types of security mechanism (e.g. WEP)
is_secure := wap.BSSDesc.Rsn != nil
// TODO: Revisit this RSSI conversion.
last_rssi := int8(wap.LastRSSI)
ap := wlan_service.Ap{bssid, wap.SSID, int32(last_rssi), is_secure}
aps = append(aps, ap)
}
return wlan_service.ScanResult{
wlan_service.Error{wlan_service.ErrCode_Ok, "OK"},
&aps,
}, nil
}
func (ws *Wlanstack) Connect(sc wlan_service.ConnectConfig) (wserr wlan_service.Error, err error) {
cli := ws.getCurrentClient()
if cli == nil {
return wlan_service.Error{
wlan_service.ErrCode_NotFound,
"No wlan interface found"}, nil
}
cfg := wlan.NewConfig()
cfg.SSID = sc.Ssid
cfg.Password = sc.PassPhrase
cfg.ScanInterval = int(sc.ScanInterval)
respC := make(chan *wlan.CommandResult, 1)
cli.PostCommand(wlan.CmdSetScanConfig, cfg, respC)
resp := <-respC
if resp.Err != nil {
return *resp.Err, nil
}
return wlan_service.Error{wlan_service.ErrCode_Ok, "OK"}, nil
}
func (ws *Wlanstack) Disconnect() (wserr wlan_service.Error, err error) {
cli := ws.getCurrentClient()
if cli == nil {
return wlan_service.Error{wlan_service.ErrCode_NotFound, "No wlan interface found"}, nil
}
respC := make(chan *wlan.CommandResult, 1)
var noArgs interface{}
cli.PostCommand(wlan.CmdDisconnect, noArgs, respC)
resp := <-respC
if resp.Err != nil {
return *resp.Err, nil
}
return wlan_service.Error{wlan_service.ErrCode_Ok, "OK"}, nil
}
func (ws *Wlanstack) Bind(r wlan_service.Wlan_Request) {
s := r.NewStub(ws, bindings.GetAsyncWaiter())
ws.stubs = append(ws.stubs, s)
go func() {
for {
if err := s.ServeRequest(); err != nil {
if mxerror.Status(err) != zx.ErrPeerClosed {
log.Println(err)
}
break
}
}
}()
}
func main() {
log.SetFlags(0)
log.SetPrefix("wlanstack: ")
log.Print("started")
ws := &Wlanstack{}
ctx := context.CreateFromStartupInfo()
ctx.OutgoingService.AddService(&wlan_service.Wlan_ServiceBinder{ws})
ctx.Serve()
ws.readConfigFile()
ws.readAPConfigFile()
const ethdir = "/dev/class/ethernet"
wt, err := watcher.NewWatcher(ethdir)
if err != nil {
log.Fatalf("ethernet: %v", err)
}
log.Printf("watching for wlan devices")
for name := range wt.C {
path := ethdir + "/" + name
if err := ws.addDevice(path); err != nil {
log.Printf("failed to add wlan device %s: %v", path, err)
}
}
}
func (ws *Wlanstack) readConfigFile() {
// TODO(tkilbourn): monitor this file for changes
// TODO(tkilbourn): replace this with a FIDL interface
const configFile = "/pkg/data/config.json"
// Once we remove the overrideFile, remove "system" access from meta/sandbox.
const overrideFile = "/system/data/wlanstack/override.json"
cfg, err := wlan.ReadConfigFromFile(overrideFile)
if err != nil {
if cfg, err = wlan.ReadConfigFromFile(configFile); err != nil {
log.Printf("[W] could not open config (%v)", configFile)
return
}
}
ws.cfg = cfg
}
func (ws *Wlanstack) readAPConfigFile() {
// TODO(hahnr): Replace once FIDL api is in place
const apConfigFile = "/pkg/data/ap_config.json"
cfg, err := wlan.ReadAPConfigFromFile(apConfigFile)
if err != nil {
log.Printf("[W] could not open config (%v)", apConfigFile)
return
}
ws.apCfg = cfg
}
func (ws *Wlanstack) addDevice(path string) error {
log.Printf("trying ethernet device %q", path)
cli, err := wlan.NewClient(path, ws.cfg, ws.apCfg)
if err != nil {
return err
}
if cli == nil {
// the device is not wlan. skip
return nil
}
log.Printf("found wlan device %q", path)
ws.mu.Lock()
ws.client = append(ws.client, cli)
ws.mu.Unlock()
go cli.Run()
return nil
}
func (ws *Wlanstack) getCurrentClient() *wlan.Client {
// Use the last client.
// TODO: Add a mechanism to choose a client
ws.mu.Lock()
defer ws.mu.Unlock()
ncli := len(ws.client)
if ncli > 0 {
return ws.client[ncli-1]
} else {
return nil
}
}