1- // Manage SoftAP (WiFi hotspot) via the hostapd HAL .
1+ // Query network management status via the INetworkManagementService system service .
22//
3- // This example demonstrates how to start and stop a WiFi access point,
4- // force-disconnect clients, and configure AP parameters using the
5- // android.hardware.wifi.hostapd HAL interface.
3+ // Uses INetworkManagementService via the "network_management" service to
4+ // list network interfaces, check tethering and firewall/bandwidth status.
65//
7- // Note: The hostapd HAL is only available on devices with real WiFi hardware.
8- // It may be blocked by SELinux for unprivileged binaries. On a real device,
9- // run as root or with the appropriate SELinux context.
6+ // Note: Some methods require root or AID_SYSTEM, and some tethering methods
7+ // were removed in Android API 36+.
108//
119// Build:
1210//
13- // GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -o build/softap_manage ./examples/softap_manage/
11+ // GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o build/softap_manage ./examples/softap_manage/
1412// adb push softap_manage /data/local/tmp/ && adb shell /data/local/tmp/softap_manage
1513package main
1614
@@ -19,28 +17,14 @@ import (
1917 "fmt"
2018 "os"
2119
20+ genOs "github.com/xaionaro-go/binder/android/os"
2221 "github.com/xaionaro-go/binder/binder"
2322 "github.com/xaionaro-go/binder/binder/versionaware"
24- "github.com/xaionaro-go/binder/android/hardware/wifi/hostapd"
2523 "github.com/xaionaro-go/binder/kernelbinder"
2624 "github.com/xaionaro-go/binder/servicemanager"
2725)
2826
29- const halServiceName = servicemanager .ServiceName ("android.hardware.wifi.hostapd.IHostapd/default" )
30-
3127func main () {
32- if len (os .Args ) < 2 {
33- fmt .Fprintf (os .Stderr , "Usage: %s <command> [args...]\n " , os .Args [0 ])
34- fmt .Fprintf (os .Stderr , "\n Commands:\n " )
35- fmt .Fprintf (os .Stderr , " start <iface> <ssid> <passphrase> Start AP on interface\n " )
36- fmt .Fprintf (os .Stderr , " stop <iface> Stop AP on interface\n " )
37- fmt .Fprintf (os .Stderr , " kick <iface> <mac_hex> Disconnect a client\n " )
38- fmt .Fprintf (os .Stderr , " terminate Terminate hostapd daemon\n " )
39- fmt .Fprintf (os .Stderr , "\n Example:\n " )
40- fmt .Fprintf (os .Stderr , " %s start wlan1 MyHotspot s3cretP4ss\n " , os .Args [0 ])
41- os .Exit (1 )
42- }
43-
4428 ctx := context .Background ()
4529
4630 driver , err := kernelbinder .Open (ctx , binder .WithMapSize (128 * 1024 ))
@@ -58,152 +42,60 @@ func main() {
5842
5943 sm := servicemanager .New (transport )
6044
61- svc , err := sm .GetService (ctx , halServiceName )
45+ svc , err := sm .GetService (ctx , servicemanager . NetworkmanagementService )
6246 if err != nil {
63- fmt .Fprintf (os .Stderr , "get hostapd HAL : %v\n " , err )
64- fmt .Fprintf (os .Stderr , "(hostapd HAL not available — no WiFi hardware or SELinux denial )\n " )
47+ fmt .Fprintf (os .Stderr , "get network_management service : %v\n " , err )
48+ fmt .Fprintf (os .Stderr , "(INetworkManagementService not available or access denied )\n " )
6549 os .Exit (1 )
6650 }
6751
68- ap := hostapd .NewHostapdProxy (svc )
69-
70- switch os .Args [1 ] {
71- case "start" :
72- cmdStart (ctx , ap )
73- case "stop" :
74- cmdStop (ctx , ap )
75- case "kick" :
76- cmdKick (ctx , ap )
77- case "terminate" :
78- cmdTerminate (ctx , ap )
79- default :
80- fmt .Fprintf (os .Stderr , "unknown command: %s\n " , os .Args [1 ])
81- os .Exit (1 )
82- }
83- }
84-
85- func cmdStart (
86- ctx context.Context ,
87- ap * hostapd.HostapdProxy ,
88- ) {
89- if len (os .Args ) < 5 {
90- fmt .Fprintf (os .Stderr , "usage: start <iface> <ssid> <passphrase>\n " )
91- os .Exit (1 )
92- }
52+ netMgr := genOs .NewNetworkManagementServiceProxy (svc )
9353
94- ifaceName := os .Args [2 ]
95- ssid := os .Args [3 ]
96- passphrase := os .Args [4 ]
97-
98- ifaceParams := hostapd.IfaceParams {
99- Name : ifaceName ,
100- HwModeParams : hostapd.HwModeParams {
101- Enable80211N : true ,
102- Enable80211AC : true ,
103- Enable80211AX : true ,
104- },
105- ChannelParams : []hostapd.ChannelParams {
106- {
107- BandMask : hostapd .BandMaskBand2Ghz ,
108- EnableAcs : true , // Let the driver pick the best channel.
109- },
110- },
111- }
112-
113- nwParams := hostapd.NetworkParams {
114- Ssid : []byte (ssid ),
115- IsHidden : false ,
116- EncryptionType : hostapd .EncryptionTypeWpa3SaeTransition ,
117- Passphrase : passphrase ,
118- }
119-
120- err := ap .AddAccessPoint (ctx , ifaceParams , nwParams )
54+ // Check tethering status (may be absent on API 36+).
55+ tethering , err := netMgr .IsTetheringStarted (ctx )
12156 if err != nil {
122- fmt .Fprintf (os .Stderr , "AddAccessPoint: %v\n " , err )
123- os .Exit (1 )
124- }
125-
126- fmt .Printf ("Access point started on %s\n " , ifaceName )
127- fmt .Printf (" SSID: %s\n " , ssid )
128- fmt .Printf (" Security: WPA3-SAE Transition\n " )
129- fmt .Printf (" Band: 2.4 GHz (ACS)\n " )
130- }
131-
132- func cmdStop (
133- ctx context.Context ,
134- ap * hostapd.HostapdProxy ,
135- ) {
136- if len (os .Args ) < 3 {
137- fmt .Fprintf (os .Stderr , "usage: stop <iface>\n " )
138- os .Exit (1 )
57+ fmt .Fprintf (os .Stderr , "IsTetheringStarted: %v\n " , err )
58+ fmt .Fprintf (os .Stderr , " (this method was removed in Android API 36)\n " )
59+ } else {
60+ fmt .Printf ("Tethering active: %v\n " , tethering )
13961 }
14062
141- ifaceName := os . Args [ 2 ]
142- err := ap . RemoveAccessPoint (ctx , ifaceName )
63+ // List tethered interfaces (may be absent on API 36+).
64+ tethered , err := netMgr . ListTetheredInterfaces (ctx )
14365 if err != nil {
144- fmt .Fprintf (os .Stderr , "RemoveAccessPoint: %v\n " , err )
145- os .Exit (1 )
146- }
147-
148- fmt .Printf ("Access point stopped on %s\n " , ifaceName )
149- }
150-
151- func cmdKick (
152- ctx context.Context ,
153- ap * hostapd.HostapdProxy ,
154- ) {
155- if len (os .Args ) < 4 {
156- fmt .Fprintf (os .Stderr , "usage: kick <iface> <mac_hex>\n " )
157- fmt .Fprintf (os .Stderr , " mac_hex: 6-byte MAC as hex, e.g. aabbccddeeff\n " )
158- os .Exit (1 )
159- }
160-
161- ifaceName := os .Args [2 ]
162- macHex := os .Args [3 ]
163-
164- mac , err := hexToBytes (macHex )
165- if err != nil || len (mac ) != 6 {
166- fmt .Fprintf (os .Stderr , "invalid MAC address: %s (need 12 hex chars)\n " , macHex )
167- os .Exit (1 )
66+ fmt .Fprintf (os .Stderr , "ListTetheredInterfaces: %v\n " , err )
67+ fmt .Fprintf (os .Stderr , " (this method was removed in Android API 36)\n " )
68+ } else if len (tethered ) == 0 {
69+ fmt .Println ("Tethered interfaces: (none)" )
70+ } else {
71+ fmt .Printf ("Tethered interfaces: %v\n " , tethered )
16872 }
16973
170- err = ap .ForceClientDisconnect (
171- ctx ,
172- ifaceName ,
173- mac ,
174- hostapd .Ieee80211ReasonCodeWlanReasonDisassocApBusy ,
175- )
74+ // List all network interfaces.
75+ ifaces , err := netMgr .ListInterfaces (ctx )
17676 if err != nil {
177- fmt .Fprintf (os .Stderr , "ForceClientDisconnect: %v\n " , err )
178- os .Exit (1 )
77+ fmt .Fprintf (os .Stderr , "ListInterfaces: %v\n " , err )
78+ } else {
79+ fmt .Printf ("\n Network interfaces (%d):\n " , len (ifaces ))
80+ for _ , iface := range ifaces {
81+ fmt .Printf (" %s\n " , iface )
82+ }
17983 }
18084
181- fmt .Printf ("Disconnected client %x from %s\n " , mac , ifaceName )
182- }
183-
184- func cmdTerminate (
185- ctx context.Context ,
186- ap * hostapd.HostapdProxy ,
187- ) {
188- err := ap .Terminate (ctx )
85+ // Check bandwidth control.
86+ fmt .Println ()
87+ bwCtrl , err := netMgr .IsBandwidthControlEnabled (ctx )
18988 if err != nil {
190- fmt .Fprintf (os .Stderr , "Terminate: %v\n " , err )
191- os .Exit (1 )
89+ fmt .Fprintf (os .Stderr , "IsBandwidthControlEnabled: %v\n " , err )
90+ } else {
91+ fmt .Printf ("Bandwidth control enabled: %v\n " , bwCtrl )
19292 }
19393
194- fmt .Println ("hostapd daemon terminated" )
195- }
196-
197- func hexToBytes (s string ) ([]byte , error ) {
198- if len (s )% 2 != 0 {
199- return nil , fmt .Errorf ("odd length hex string" )
200- }
201- b := make ([]byte , len (s )/ 2 )
202- for i := range b {
203- _ , err := fmt .Sscanf (s [2 * i :2 * i + 2 ], "%02x" , & b [i ])
204- if err != nil {
205- return nil , err
206- }
94+ // Check firewall status (requires AID_SYSTEM).
95+ fwEnabled , err := netMgr .IsFirewallEnabled (ctx )
96+ if err != nil {
97+ fmt .Fprintf (os .Stderr , "IsFirewallEnabled: %v (requires AID_SYSTEM)\n " , err )
98+ } else {
99+ fmt .Printf ("Firewall enabled: %v\n " , fwEnabled )
207100 }
208- return b , nil
209101}
0 commit comments