mirror of
https://github.com/Team254/cheesy-arena-lite.git
synced 2026-03-10 06:06:47 -04:00
Rewrite access point configuration logic to use uci instead of uploading the whole wireless file each time.
This commit is contained in:
Binary file not shown.
@@ -6,15 +6,13 @@
|
||||
package field
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"golang.org/x/crypto/ssh"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"text/template"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -23,15 +21,6 @@ const accessPointConnectTimeoutSec = 1
|
||||
const accessPointCommandTimeoutSec = 3
|
||||
const accessPointRetryCount = 2
|
||||
|
||||
const (
|
||||
red1Vlan = 10
|
||||
red2Vlan = 20
|
||||
red3Vlan = 30
|
||||
blue1Vlan = 40
|
||||
blue2Vlan = 50
|
||||
blue3Vlan = 60
|
||||
)
|
||||
|
||||
type AccessPoint struct {
|
||||
address string
|
||||
port int
|
||||
@@ -58,16 +47,22 @@ func (ap *AccessPoint) ConfigureTeamWifi(red1, red2, red3, blue1, blue2, blue3 *
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
command := fmt.Sprintf("cat <<ENDCONFIG > /etc/config/wireless && wifi radio0\n%sENDCONFIG\n", config)
|
||||
command := fmt.Sprintf("uci batch <<ENDCONFIG && wifi radio0\n%s\nENDCONFIG\n", config)
|
||||
return ap.runCommand(command)
|
||||
}
|
||||
|
||||
func (ap *AccessPoint) ConfigureAdminWifi() error {
|
||||
config, err := ap.generateAccessPointConfig(nil, nil, nil, nil, nil, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
// Make sure multiple configurations aren't being set at the same time.
|
||||
ap.mutex.Lock()
|
||||
defer ap.mutex.Unlock()
|
||||
|
||||
commands := []string{
|
||||
fmt.Sprintf("set wireless.radio0.channel='%d'", ap.teamChannel),
|
||||
fmt.Sprintf("set wireless.radio1.channel='%d'", ap.adminChannel),
|
||||
fmt.Sprintf("set wireless.@wifi-iface[0].key='%s'", ap.adminWpaKey),
|
||||
"commit wireless",
|
||||
}
|
||||
command := fmt.Sprintf("cat <<ENDCONFIG > /etc/config/wireless && wifi radio1\n%sENDCONFIG\n", config)
|
||||
command := fmt.Sprintf("uci batch <<ENDCONFIG && wifi\n%s\nENDCONFIG\n", strings.Join(commands, "\n"))
|
||||
return ap.runCommand(command)
|
||||
}
|
||||
|
||||
@@ -122,55 +117,43 @@ func (ap *AccessPoint) runCommand(command string) error {
|
||||
|
||||
func (ap *AccessPoint) generateAccessPointConfig(red1, red2, red3, blue1, blue2, blue3 *model.Team) (string, error) {
|
||||
// Determine what new SSIDs are needed.
|
||||
networks := make(map[int]*model.Team)
|
||||
commands := &[]string{}
|
||||
var err error
|
||||
if err = addTeamNetwork(networks, red1, red1Vlan); err != nil {
|
||||
if err = addTeamConfigCommands(1, red1, commands); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = addTeamNetwork(networks, red2, red2Vlan); err != nil {
|
||||
if err = addTeamConfigCommands(2, red2, commands); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = addTeamNetwork(networks, red3, red3Vlan); err != nil {
|
||||
if err = addTeamConfigCommands(3, red3, commands); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = addTeamNetwork(networks, blue1, blue1Vlan); err != nil {
|
||||
if err = addTeamConfigCommands(4, blue1, commands); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = addTeamNetwork(networks, blue2, blue2Vlan); err != nil {
|
||||
if err = addTeamConfigCommands(5, blue2, commands); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err = addTeamNetwork(networks, blue3, blue3Vlan); err != nil {
|
||||
if err = addTeamConfigCommands(6, blue3, commands); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Generate the config file to be uploaded to the AP.
|
||||
template, err := template.ParseFiles(filepath.Join(model.BaseDir, "templates/access_point.cfg"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
data := struct {
|
||||
Networks map[int]*model.Team
|
||||
TeamChannel int
|
||||
AdminChannel int
|
||||
AdminWpaKey string
|
||||
}{networks, ap.teamChannel, ap.adminChannel, ap.adminWpaKey}
|
||||
var configFile bytes.Buffer
|
||||
err = template.Execute(&configFile, data)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
*commands = append(*commands, "commit wireless")
|
||||
|
||||
return configFile.String(), nil
|
||||
return strings.Join(*commands, "\n"), nil
|
||||
}
|
||||
|
||||
// Verifies the validity of the given team's WPA key and adds a network for it to the list to be configured.
|
||||
func addTeamNetwork(networks map[int]*model.Team, team *model.Team, vlan int) error {
|
||||
func addTeamConfigCommands(position int, team *model.Team, commands *[]string) error {
|
||||
if team == nil {
|
||||
return nil
|
||||
}
|
||||
if len(team.WpaKey) < 8 || len(team.WpaKey) > 63 {
|
||||
return fmt.Errorf("Invalid WPA key '%s' configured for team %d.", team.WpaKey, team.Id)
|
||||
}
|
||||
networks[vlan] = team
|
||||
|
||||
*commands = append(*commands, fmt.Sprintf("set wireless.@wifi-iface[%d].ssid='%d'", position, team.Id),
|
||||
fmt.Sprintf("set wireless.@wifi-iface[%d].key='%s'", position, team.WpaKey))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,80 +7,57 @@ import (
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConfigureAccessPoint(t *testing.T) {
|
||||
model.BaseDir = ".."
|
||||
|
||||
radioRe := regexp.MustCompile("option device 'radio0'")
|
||||
ssidRe := regexp.MustCompile("option ssid '([-\\w ]+)'")
|
||||
wpaKeyRe := regexp.MustCompile("option key '([-\\w ]+)'")
|
||||
vlanRe := regexp.MustCompile("option network 'vlan(\\d+)'")
|
||||
channelRe := regexp.MustCompile("option channel '(\\d+)'")
|
||||
ssidRe := regexp.MustCompile("ssid='([-\\w ]+)'")
|
||||
wpaKeyRe := regexp.MustCompile("key='([-\\w ]+)'")
|
||||
ap := AccessPoint{teamChannel: 1234, adminChannel: 4321, adminWpaKey: "blorpy"}
|
||||
|
||||
// Should not configure any team SSIDs if there are no teams.
|
||||
config, _ := ap.generateAccessPointConfig(nil, nil, nil, nil, nil, nil)
|
||||
assert.NotContains(t, config, "option device 'radio0'")
|
||||
assert.NotContains(t, config, "set")
|
||||
ssids := ssidRe.FindAllStringSubmatch(config, -1)
|
||||
wpaKeys := wpaKeyRe.FindAllStringSubmatch(config, -1)
|
||||
vlans := vlanRe.FindAllStringSubmatch(config, -1)
|
||||
channels := channelRe.FindAllStringSubmatch(config, -1)
|
||||
assert.Equal(t, "Cheesy Arena", ssids[0][1])
|
||||
assert.Equal(t, ap.adminWpaKey, wpaKeys[0][1])
|
||||
assert.Equal(t, "100", vlans[0][1])
|
||||
assert.Equal(t, strconv.Itoa(ap.adminChannel), channels[0][1])
|
||||
assert.Equal(t, strconv.Itoa(ap.teamChannel), channels[1][1])
|
||||
assert.Equal(t, 0, len(ssids))
|
||||
assert.Equal(t, 0, len(wpaKeys))
|
||||
|
||||
// Should configure two SSID for two teams.
|
||||
config, _ = ap.generateAccessPointConfig(&model.Team{Id: 254, WpaKey: "aaaaaaaa"}, nil, nil, nil, nil,
|
||||
&model.Team{Id: 1114, WpaKey: "bbbbbbbb"})
|
||||
assert.Equal(t, 2, len(radioRe.FindAllString(config, -1)))
|
||||
ssids = ssidRe.FindAllStringSubmatch(config, -1)
|
||||
wpaKeys = wpaKeyRe.FindAllStringSubmatch(config, -1)
|
||||
vlans = vlanRe.FindAllStringSubmatch(config, -1)
|
||||
assert.Equal(t, "Cheesy Arena", ssids[0][1])
|
||||
assert.Equal(t, ap.adminWpaKey, wpaKeys[0][1])
|
||||
assert.Equal(t, "100", vlans[0][1])
|
||||
assert.Equal(t, "254", ssids[1][1])
|
||||
assert.Equal(t, "aaaaaaaa", wpaKeys[1][1])
|
||||
assert.Equal(t, "10", vlans[1][1])
|
||||
assert.Equal(t, "1114", ssids[2][1])
|
||||
assert.Equal(t, "bbbbbbbb", wpaKeys[2][1])
|
||||
assert.Equal(t, "60", vlans[2][1])
|
||||
if assert.Equal(t, 2, len(ssids)) && assert.Equal(t, 2, len(wpaKeys)) {
|
||||
assert.Equal(t, "254", ssids[0][1])
|
||||
assert.Equal(t, "aaaaaaaa", wpaKeys[0][1])
|
||||
assert.Equal(t, "1114", ssids[1][1])
|
||||
assert.Equal(t, "bbbbbbbb", wpaKeys[1][1])
|
||||
}
|
||||
|
||||
// Should configure all SSIDs for six teams.
|
||||
config, _ = ap.generateAccessPointConfig(&model.Team{Id: 1, WpaKey: "11111111"},
|
||||
&model.Team{Id: 2, WpaKey: "22222222"}, &model.Team{Id: 3, WpaKey: "33333333"},
|
||||
&model.Team{Id: 4, WpaKey: "44444444"}, &model.Team{Id: 5, WpaKey: "55555555"},
|
||||
&model.Team{Id: 6, WpaKey: "66666666"})
|
||||
assert.Equal(t, 6, len(radioRe.FindAllString(config, -1)))
|
||||
ssids = ssidRe.FindAllStringSubmatch(config, -1)
|
||||
wpaKeys = wpaKeyRe.FindAllStringSubmatch(config, -1)
|
||||
vlans = vlanRe.FindAllStringSubmatch(config, -1)
|
||||
assert.Equal(t, "Cheesy Arena", ssids[0][1])
|
||||
assert.Equal(t, ap.adminWpaKey, wpaKeys[0][1])
|
||||
assert.Equal(t, "100", vlans[0][1])
|
||||
assert.Equal(t, "1", ssids[1][1])
|
||||
assert.Equal(t, "11111111", wpaKeys[1][1])
|
||||
assert.Equal(t, "10", vlans[1][1])
|
||||
assert.Equal(t, "2", ssids[2][1])
|
||||
assert.Equal(t, "22222222", wpaKeys[2][1])
|
||||
assert.Equal(t, "20", vlans[2][1])
|
||||
assert.Equal(t, "3", ssids[3][1])
|
||||
assert.Equal(t, "33333333", wpaKeys[3][1])
|
||||
assert.Equal(t, "30", vlans[3][1])
|
||||
assert.Equal(t, "4", ssids[4][1])
|
||||
assert.Equal(t, "44444444", wpaKeys[4][1])
|
||||
assert.Equal(t, "40", vlans[4][1])
|
||||
assert.Equal(t, "5", ssids[5][1])
|
||||
assert.Equal(t, "55555555", wpaKeys[5][1])
|
||||
assert.Equal(t, "50", vlans[5][1])
|
||||
assert.Equal(t, "6", ssids[6][1])
|
||||
assert.Equal(t, "66666666", wpaKeys[6][1])
|
||||
assert.Equal(t, "60", vlans[6][1])
|
||||
if assert.Equal(t, 6, len(ssids)) && assert.Equal(t, 6, len(wpaKeys)) {
|
||||
assert.Equal(t, "1", ssids[0][1])
|
||||
assert.Equal(t, "11111111", wpaKeys[0][1])
|
||||
assert.Equal(t, "2", ssids[1][1])
|
||||
assert.Equal(t, "22222222", wpaKeys[1][1])
|
||||
assert.Equal(t, "3", ssids[2][1])
|
||||
assert.Equal(t, "33333333", wpaKeys[2][1])
|
||||
assert.Equal(t, "4", ssids[3][1])
|
||||
assert.Equal(t, "44444444", wpaKeys[3][1])
|
||||
assert.Equal(t, "5", ssids[4][1])
|
||||
assert.Equal(t, "55555555", wpaKeys[4][1])
|
||||
assert.Equal(t, "6", ssids[5][1])
|
||||
assert.Equal(t, "66666666", wpaKeys[5][1])
|
||||
}
|
||||
|
||||
// Should reject a missing WPA key.
|
||||
_, err := ap.generateAccessPointConfig(&model.Team{Id: 254}, nil, nil, nil, nil, nil)
|
||||
|
||||
@@ -18,6 +18,15 @@ import (
|
||||
|
||||
const switchTelnetPort = 23
|
||||
|
||||
const (
|
||||
red1Vlan = 10
|
||||
red2Vlan = 20
|
||||
red3Vlan = 30
|
||||
blue1Vlan = 40
|
||||
blue2Vlan = 50
|
||||
blue3Vlan = 60
|
||||
)
|
||||
|
||||
type NetworkSwitch struct {
|
||||
address string
|
||||
port int
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
config wifi-device 'radio1'
|
||||
option type 'mac80211'
|
||||
option channel '{{.AdminChannel}}'
|
||||
option hwmode '11g'
|
||||
option path 'soc/soc:pcie-controller/pci0000:00/0000:00:02.0/0000:02:00.0'
|
||||
option htmode 'HT20'
|
||||
option disabled '0'
|
||||
option txpower '20'
|
||||
option country 'US'
|
||||
|
||||
config wifi-iface
|
||||
option device 'radio1'
|
||||
option mode 'ap'
|
||||
option hidden '1'
|
||||
option encryption 'psk2+ccmp'
|
||||
option network 'vlan100'
|
||||
option ssid 'Cheesy Arena'
|
||||
option key '{{.AdminWpaKey}}'
|
||||
option macaddr '62:38:e0:12:6b:17'
|
||||
|
||||
config wifi-device 'radio0'
|
||||
option type 'mac80211'
|
||||
option hwmode '11a'
|
||||
option path 'soc/soc:pcie-controller/pci0000:00/0000:00:01.0/0000:01:00.0'
|
||||
option txpower '23'
|
||||
option channel '{{.TeamChannel}}'
|
||||
option country 'US'
|
||||
option htmode 'HT20'
|
||||
option basic_rates '6500,7200'
|
||||
option short_gi_20 '0'
|
||||
|
||||
{{range $vlan, $team := .Networks}}
|
||||
config wifi-iface
|
||||
option device 'radio0'
|
||||
option mode 'ap'
|
||||
option isolate '0'
|
||||
option bgscan '0'
|
||||
option wds '0'
|
||||
option maxassoc '1'
|
||||
option hidden '1'
|
||||
option network 'vlan{{$vlan}}'
|
||||
option encryption 'psk2+ccmp'
|
||||
option ssid '{{$team.Id}}'
|
||||
option key '{{$team.WpaKey}}'
|
||||
option disabled '0'
|
||||
{{end}}
|
||||
Reference in New Issue
Block a user