mirror of
https://github.com/0x1d/rcond.git
synced 2025-12-14 18:25:21 +01:00
initial commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
bin
|
||||
19
Makefile
Normal file
19
Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
ARCH ?= arm64
|
||||
ADDR ?= 0.0.0.0:8080
|
||||
|
||||
generate:
|
||||
swagger generate server -f api/rcond.yaml -t api/
|
||||
go mod tidy
|
||||
|
||||
build:
|
||||
mkdir -p bin
|
||||
env GOOS=linux GOARCH=${ARCH} go build -o bin/rcond-${ARCH} ./cmd/rcond/main.go
|
||||
|
||||
run:
|
||||
bin/rcond-${ARCH} ${ADDR}
|
||||
|
||||
dev:
|
||||
go run cmd/rcond/main.go ${ADDR}
|
||||
|
||||
upload:
|
||||
scp rcond-${ARCH} pi@rpi-40ac:/home/pi/rcond
|
||||
68
README.md
Normal file
68
README.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# rcond
|
||||
|
||||
A simple daemon to manage network connections through NetworkManager's D-Bus interface.
|
||||
|
||||
It provides a REST API to:
|
||||
- Create and activate WiFi connections
|
||||
- Deactivate WiFi connections
|
||||
- Remove stored connection profiles
|
||||
|
||||
The daemon is designed to run on Linux systems with NetworkManager.
|
||||
|
||||
## Build and Run
|
||||
|
||||
```bash
|
||||
make build
|
||||
make run
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
The full API specification can be found in [api/rcond.yaml](api/rcond.yaml).
|
||||
|
||||
### Endpoints
|
||||
|
||||
| Method | Path | Description |
|
||||
|--------|------|-------------|
|
||||
| GET | `/health` | Health check endpoint that returns status |
|
||||
| POST | `/network/up` | Create and activate a WiFi access point |
|
||||
| POST | `/network/down` | Deactivate a WiFi interface |
|
||||
| POST | `/network/remove` | Remove the stored connection profile |
|
||||
|
||||
### Response Codes
|
||||
|
||||
- 200: Success
|
||||
- 400: Bad request (invalid JSON payload)
|
||||
- 405: Method not allowed
|
||||
- 500: Internal server error
|
||||
|
||||
### Request/Response Format
|
||||
All endpoints use JSON for request and response payloads.
|
||||
|
||||
### 1) Bring a network up
|
||||
|
||||
```bash
|
||||
curl -v -X POST http://localhost:8080/network/up \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"interface": "wlan0",
|
||||
"ssid": "MyNetworkSSID",
|
||||
"password": "SuperSecretPassword"
|
||||
}'
|
||||
```
|
||||
|
||||
### 2) Bring a network down
|
||||
|
||||
```bash
|
||||
curl -v -X POST http://localhost:8080/network/down \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"interface": "wlan0"
|
||||
}'
|
||||
```
|
||||
|
||||
### 3) Remove the stored connection
|
||||
|
||||
```bash
|
||||
curl -v -X POST http://localhost:8080/network/remove
|
||||
```
|
||||
96
api/rcond.yaml
Normal file
96
api/rcond.yaml
Normal file
@@ -0,0 +1,96 @@
|
||||
openapi: 3.0.0
|
||||
info:
|
||||
title: rcond API
|
||||
description: API for managing network connections through NetworkManager
|
||||
version: 1.0.0
|
||||
|
||||
servers:
|
||||
- url: http://localhost:8080
|
||||
description: Local development server
|
||||
|
||||
paths:
|
||||
/health:
|
||||
get:
|
||||
summary: Health check endpoint
|
||||
description: Returns the health status of the service
|
||||
responses:
|
||||
'200':
|
||||
description: Service is healthy
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
example: "healthy"
|
||||
|
||||
/network/up:
|
||||
post:
|
||||
summary: Create and activate WiFi access point
|
||||
description: Creates and activates a WiFi access point on the specified interface
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- interface
|
||||
- ssid
|
||||
- password
|
||||
properties:
|
||||
interface:
|
||||
type: string
|
||||
description: Network interface name
|
||||
example: "wlan0"
|
||||
ssid:
|
||||
type: string
|
||||
description: WiFi network SSID
|
||||
example: "MyNetworkSSID"
|
||||
password:
|
||||
type: string
|
||||
description: WiFi network password
|
||||
example: "SuperSecretPassword"
|
||||
responses:
|
||||
'200':
|
||||
description: Network interface brought up successfully
|
||||
'400':
|
||||
description: Invalid request payload
|
||||
'500':
|
||||
description: Internal server error
|
||||
|
||||
/network/down:
|
||||
post:
|
||||
summary: Deactivate network interface
|
||||
description: Deactivates the specified network interface
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- interface
|
||||
properties:
|
||||
interface:
|
||||
type: string
|
||||
description: Network interface name
|
||||
example: "wlan0"
|
||||
responses:
|
||||
'200':
|
||||
description: Network interface brought down successfully
|
||||
'400':
|
||||
description: Invalid request payload
|
||||
'500':
|
||||
description: Internal server error
|
||||
|
||||
/network/remove:
|
||||
post:
|
||||
summary: Remove stored connection profile
|
||||
description: Removes the stored NetworkManager connection profile
|
||||
responses:
|
||||
'200':
|
||||
description: Connection profile removed successfully
|
||||
'500':
|
||||
description: Internal server error
|
||||
35
cmd/rcond/main.go
Normal file
35
cmd/rcond/main.go
Normal file
@@ -0,0 +1,35 @@
|
||||
// Usage: rcond <address>
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
http "github.com/0x1d/rcond/pkg/http"
|
||||
)
|
||||
|
||||
const (
|
||||
NETWORK_CONNECTION_UUID = "7d706027-727c-4d4c-a816-f0e1b99db8ab"
|
||||
)
|
||||
|
||||
func usage() {
|
||||
fmt.Printf("Usage: %s <address>\n", os.Args[0])
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
usage()
|
||||
}
|
||||
|
||||
addr := os.Args[1]
|
||||
srv := http.NewServer(addr)
|
||||
srv.RegisterRoutes()
|
||||
|
||||
log.Printf("Starting server on %s", addr)
|
||||
if err := srv.Start(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
12
go.mod
Normal file
12
go.mod
Normal file
@@ -0,0 +1,12 @@
|
||||
module github.com/0x1d/rcond
|
||||
|
||||
go 1.23.4
|
||||
|
||||
replace github.com/0x1d/rcond/cmd => ./cmd
|
||||
|
||||
replace github.com/0x1d/rcond/pkg => ./pkg
|
||||
|
||||
require (
|
||||
github.com/godbus/dbus/v5 v5.1.0
|
||||
github.com/gorilla/mux v1.8.1
|
||||
)
|
||||
4
go.sum
Normal file
4
go.sum
Normal file
@@ -0,0 +1,4 @@
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
78
pkg/http/handlers.go
Normal file
78
pkg/http/handlers.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/0x1d/rcond/pkg/network"
|
||||
)
|
||||
|
||||
const (
|
||||
NETWORK_CONNECTION_UUID = "7d706027-727c-4d4c-a816-f0e1b99db8ab"
|
||||
)
|
||||
|
||||
func HandleNetworkUp(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Interface string `json:"interface"`
|
||||
SSID string `json:"ssid"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("Bringing up network interface %s with SSID %s", req.Interface, req.SSID)
|
||||
if err := network.Up(req.Interface, req.SSID, req.Password, NETWORK_CONNECTION_UUID); err != nil {
|
||||
log.Printf("Failed to bring up network interface %s: %v", req.Interface, err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
log.Printf("Successfully brought up network interface %s", req.Interface)
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func HandleNetworkDown(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
Interface string `json:"interface"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if err := network.Down(req.Interface); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func HandleNetworkRemove(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
if err := network.Remove(NETWORK_CONNECTION_UUID); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.WriteHeader(http.StatusOK)
|
||||
}
|
||||
53
pkg/http/server.go
Normal file
53
pkg/http/server.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
router *mux.Router
|
||||
srv *http.Server
|
||||
}
|
||||
|
||||
func NewServer(addr string) *Server {
|
||||
router := mux.NewRouter()
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: addr,
|
||||
Handler: router,
|
||||
ReadTimeout: 15 * time.Second,
|
||||
WriteTimeout: 15 * time.Second,
|
||||
}
|
||||
|
||||
return &Server{
|
||||
router: router,
|
||||
srv: srv,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Start() error {
|
||||
return s.srv.ListenAndServe()
|
||||
}
|
||||
|
||||
func (s *Server) Shutdown(ctx context.Context) error {
|
||||
return s.srv.Shutdown(ctx)
|
||||
}
|
||||
|
||||
func (s *Server) RegisterRoutes() {
|
||||
s.router.HandleFunc("/health", s.healthHandler).Methods(http.MethodGet)
|
||||
s.router.HandleFunc("/network/up", HandleNetworkUp).Methods(http.MethodPost)
|
||||
s.router.HandleFunc("/network/down", HandleNetworkDown).Methods(http.MethodPost)
|
||||
s.router.HandleFunc("/network/remove", HandleNetworkRemove).Methods(http.MethodPost)
|
||||
}
|
||||
|
||||
func (s *Server) healthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "healthy",
|
||||
})
|
||||
}
|
||||
330
pkg/network/nm.go
Normal file
330
pkg/network/nm.go
Normal file
@@ -0,0 +1,330 @@
|
||||
package network
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/godbus/dbus/v5"
|
||||
)
|
||||
|
||||
const (
|
||||
ourUUID = "7d706027-727c-4d4c-a816-f0e1b99db8ab"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultSSID = "PIAP"
|
||||
defaultPassword = "raspberry"
|
||||
)
|
||||
|
||||
// withDbus executes the given function with a D-Bus system connection
|
||||
// and handles any connection errors
|
||||
func withDbus(fn func(*dbus.Conn) error) error {
|
||||
conn, err := dbus.SystemBus()
|
||||
if err != nil {
|
||||
log.Printf("Failed to connect to system bus: %v", err)
|
||||
return err
|
||||
}
|
||||
if err := fn(conn); err != nil {
|
||||
log.Print(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ActivateConnection activates a NetworkManager connection profile.
|
||||
// It takes a D-Bus connection, connection profile path, and device path as arguments.
|
||||
// The function waits up to 10 seconds for the connection to become active.
|
||||
// Returns an error if activation fails or times out.
|
||||
func ActivateConnection(conn *dbus.Conn, connPath, devPath dbus.ObjectPath) error {
|
||||
nmObj := conn.Object(
|
||||
"org.freedesktop.NetworkManager",
|
||||
"/org/freedesktop/NetworkManager",
|
||||
)
|
||||
|
||||
// Activate the connection
|
||||
var activePath dbus.ObjectPath
|
||||
err := nmObj.
|
||||
Call("org.freedesktop.NetworkManager.ActivateConnection", 0,
|
||||
connPath, devPath, dbus.ObjectPath("/")).
|
||||
Store(&activePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("ActivateConnection failed: %v", err)
|
||||
}
|
||||
|
||||
// Wait until the connection is activated
|
||||
props := conn.Object(
|
||||
"org.freedesktop.NetworkManager",
|
||||
activePath,
|
||||
)
|
||||
|
||||
start := time.Now()
|
||||
for time.Since(start) < 10*time.Second {
|
||||
var stateVar dbus.Variant
|
||||
err = props.
|
||||
Call("org.freedesktop.DBus.Properties.Get", 0,
|
||||
"org.freedesktop.NetworkManager.Connection.Active",
|
||||
"State").
|
||||
Store(&stateVar)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Properties.Get(State) failed: %v", err)
|
||||
}
|
||||
if state, ok := stateVar.Value().(uint32); ok && state == 2 {
|
||||
log.Printf("Connection activated on connection path %v", connPath)
|
||||
return nil
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
return fmt.Errorf("failed to activate connection")
|
||||
}
|
||||
|
||||
// DisconnectDevice disconnects a NetworkManager device, stopping any active connections.
|
||||
// Takes a D-Bus connection and device path as arguments.
|
||||
// Returns an error if the disconnect operation fails.
|
||||
func DisconnectDevice(conn *dbus.Conn, devPath dbus.ObjectPath) error {
|
||||
devObj := conn.Object(
|
||||
"org.freedesktop.NetworkManager",
|
||||
devPath,
|
||||
)
|
||||
err := devObj.
|
||||
Call("org.freedesktop.NetworkManager.Device.Disconnect", 0).
|
||||
Err
|
||||
if err != nil {
|
||||
return fmt.Errorf("Device.Disconnect failed: %v", err)
|
||||
}
|
||||
fmt.Println("Access point stopped")
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteConnection removes a NetworkManager connection profile.
|
||||
// Takes a D-Bus connection and connection profile path as arguments.
|
||||
// Returns an error if the delete operation fails.
|
||||
func DeleteConnection(conn *dbus.Conn, connPath dbus.ObjectPath) error {
|
||||
connObj := conn.Object(
|
||||
"org.freedesktop.NetworkManager",
|
||||
connPath,
|
||||
)
|
||||
err := connObj.
|
||||
Call("org.freedesktop.NetworkManager.Settings.Connection.Delete", 0).
|
||||
Err
|
||||
if err != nil {
|
||||
return fmt.Errorf("Connection.Delete failed: %v", err)
|
||||
}
|
||||
log.Printf("Connection removed: %v", connPath)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetWifiConfig retrieves the WiFi SSID and password from environment variables or command line arguments.
|
||||
// Takes an operation string ("up", "down", etc) to determine whether to check command line args.
|
||||
// Returns the SSID and password strings.
|
||||
// Priority order: command line args > environment variables > default values
|
||||
func GetWifiConfig(op string) (string, string) {
|
||||
// Get SSID and password from args, env vars or use defaults
|
||||
ssid := defaultSSID
|
||||
password := defaultPassword
|
||||
|
||||
// Check environment variables first
|
||||
if v, ok := os.LookupEnv("WIFI_SSID"); ok {
|
||||
ssid = v
|
||||
}
|
||||
if v, ok := os.LookupEnv("WIFI_PASSWORD"); ok {
|
||||
password = v
|
||||
}
|
||||
|
||||
// Command line args override environment variables
|
||||
if op == "up" && len(os.Args) >= 5 {
|
||||
ssid = os.Args[3]
|
||||
password = os.Args[4]
|
||||
}
|
||||
|
||||
return ssid, password
|
||||
}
|
||||
|
||||
// GetConnectionPath looks up a NetworkManager connection profile by UUID.
|
||||
// Takes a D-Bus connection and connection UUID string as arguments.
|
||||
// Returns the D-Bus object path of the connection if found, or empty string if not found.
|
||||
// Returns an error if the lookup operation fails.
|
||||
func GetConnectionPath(conn *dbus.Conn, connUUID string) (dbus.ObjectPath, error) {
|
||||
// Get the Settings interface
|
||||
settingsObj := conn.Object(
|
||||
"org.freedesktop.NetworkManager",
|
||||
"/org/freedesktop/NetworkManager/Settings",
|
||||
)
|
||||
|
||||
// List existing connections
|
||||
var paths []dbus.ObjectPath
|
||||
err := settingsObj.
|
||||
Call("org.freedesktop.NetworkManager.Settings.ListConnections", 0).
|
||||
Store(&paths)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("ListConnections failed: %v", err)
|
||||
}
|
||||
|
||||
// Look up our connection by UUID
|
||||
var connPath dbus.ObjectPath
|
||||
for _, p := range paths {
|
||||
obj := conn.Object(
|
||||
"org.freedesktop.NetworkManager",
|
||||
p,
|
||||
)
|
||||
var cfg map[string]map[string]dbus.Variant
|
||||
err = obj.
|
||||
Call("org.freedesktop.NetworkManager.Settings.Connection.GetSettings", 0).
|
||||
Store(&cfg)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if v, ok := cfg["connection"]["uuid"].Value().(string); ok && v == connUUID {
|
||||
connPath = p
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return connPath, nil
|
||||
}
|
||||
|
||||
// AddConnection creates a new NetworkManager connection profile for a WiFi access point.
|
||||
// Takes a D-Bus connection, SSID string, and password string as arguments.
|
||||
// Returns the D-Bus object path of the new connection profile.
|
||||
// Returns an error if the connection creation fails.
|
||||
func AddConnection(conn *dbus.Conn, ssid string, password string) (dbus.ObjectPath, error) {
|
||||
settingsObj := conn.Object(
|
||||
"org.freedesktop.NetworkManager",
|
||||
"/org/freedesktop/NetworkManager/Settings",
|
||||
)
|
||||
|
||||
settingsMap := map[string]map[string]dbus.Variant{
|
||||
"connection": {
|
||||
"type": dbus.MakeVariant("802-11-wireless"),
|
||||
"uuid": dbus.MakeVariant(ourUUID),
|
||||
"id": dbus.MakeVariant(ssid),
|
||||
"autoconnect": dbus.MakeVariant(true),
|
||||
},
|
||||
"802-11-wireless": {
|
||||
"ssid": dbus.MakeVariant([]byte(ssid)),
|
||||
"mode": dbus.MakeVariant("ap"),
|
||||
"band": dbus.MakeVariant("bg"),
|
||||
"channel": dbus.MakeVariant(uint32(1)),
|
||||
},
|
||||
"802-11-wireless-security": {
|
||||
"key-mgmt": dbus.MakeVariant("wpa-psk"),
|
||||
"psk": dbus.MakeVariant(password),
|
||||
},
|
||||
"ipv4": {
|
||||
"method": dbus.MakeVariant("shared"),
|
||||
},
|
||||
"ipv6": {
|
||||
"method": dbus.MakeVariant("ignore"),
|
||||
},
|
||||
}
|
||||
|
||||
var connPath dbus.ObjectPath
|
||||
err := settingsObj.
|
||||
Call("org.freedesktop.NetworkManager.Settings.AddConnection", 0, settingsMap).
|
||||
Store(&connPath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("AddConnection failed: %v", err)
|
||||
}
|
||||
|
||||
return connPath, nil
|
||||
}
|
||||
|
||||
// GetDeviceByIpIface looks up a NetworkManager device by its interface name.
|
||||
// Takes a D-Bus connection and interface name string as arguments.
|
||||
// Returns the D-Bus object path of the device.
|
||||
// Returns an error if the device lookup fails.
|
||||
func GetDeviceByIpIface(conn *dbus.Conn, iface string) (dbus.ObjectPath, error) {
|
||||
// Get the NetworkManager interface
|
||||
nmObj := conn.Object(
|
||||
"org.freedesktop.NetworkManager",
|
||||
"/org/freedesktop/NetworkManager",
|
||||
)
|
||||
|
||||
// Find the device by interface name
|
||||
var devPath dbus.ObjectPath
|
||||
err := nmObj.
|
||||
Call("org.freedesktop.NetworkManager.GetDeviceByIpIface", 0, iface).
|
||||
Store(&devPath)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("GetDeviceByIpIface(%s) failed: %v", iface, err)
|
||||
}
|
||||
|
||||
return devPath, nil
|
||||
}
|
||||
|
||||
// Up creates and activates a WiFi access point connection.
|
||||
// It takes the interface name, SSID, password and UUID as arguments.
|
||||
// If a connection with the given UUID exists, it will be reused.
|
||||
// Otherwise, a new connection will be created.
|
||||
// The connection will be activated on the specified interface.
|
||||
// Returns an error if any operation fails.
|
||||
func Up(iface string, ssid string, password string, uuid string) error {
|
||||
return withDbus(func(conn *dbus.Conn) error {
|
||||
connPath, err := GetConnectionPath(conn, uuid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if connPath == "" {
|
||||
connPath, err = AddConnection(conn, ssid, password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("Getting device path for interface %s", iface)
|
||||
devPath, err := GetDeviceByIpIface(conn, iface)
|
||||
if err != nil {
|
||||
log.Printf("Failed to get device path for interface %s: %v", iface, err)
|
||||
return err
|
||||
}
|
||||
log.Printf("Got device path %s for interface %s", devPath, iface)
|
||||
|
||||
if err := ActivateConnection(conn, connPath, devPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Down deactivates a network connection on the specified interface.
|
||||
// It takes the interface name as an argument.
|
||||
// Returns an error if the device cannot be found or disconnected.
|
||||
func Down(iface string) error {
|
||||
return withDbus(func(conn *dbus.Conn) error {
|
||||
devPath, err := GetDeviceByIpIface(conn, iface)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := DisconnectDevice(conn, devPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// Remove deletes a NetworkManager connection profile with the given UUID.
|
||||
// If no connection with the UUID exists, it returns nil.
|
||||
// Returns an error if the connection exists but cannot be deleted.
|
||||
func Remove(uuid string) error {
|
||||
return withDbus(func(conn *dbus.Conn) error {
|
||||
connPath, err := GetConnectionPath(conn, uuid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if connPath == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := DeleteConnection(conn, connPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user