2013-03-19 00:53:09 +01:00
|
|
|
#!/usr/bin/python
|
|
|
|
#
|
|
|
|
# wpa_supplicant/hostapd control interface using Python
|
|
|
|
# Copyright (c) 2013, Jouni Malinen <j@w1.fi>
|
|
|
|
#
|
|
|
|
# This software may be distributed under the terms of the BSD license.
|
|
|
|
# See README for more details.
|
|
|
|
|
|
|
|
import os
|
2016-03-04 10:20:32 +01:00
|
|
|
import stat
|
2013-03-19 00:53:09 +01:00
|
|
|
import socket
|
|
|
|
import select
|
|
|
|
|
|
|
|
counter = 0
|
|
|
|
|
|
|
|
class Ctrl:
|
2016-03-04 10:20:32 +01:00
|
|
|
def __init__(self, path, port=9877):
|
2013-03-19 00:53:09 +01:00
|
|
|
global counter
|
|
|
|
self.started = False
|
|
|
|
self.attached = False
|
2016-03-04 10:20:32 +01:00
|
|
|
self.path = path
|
|
|
|
self.port = port
|
|
|
|
|
2021-03-01 11:51:20 +01:00
|
|
|
self.udp = False
|
|
|
|
if not path.startswith('/'):
|
|
|
|
try:
|
|
|
|
mode = os.stat(path).st_mode
|
|
|
|
if not stat.S_ISSOCK(mode):
|
|
|
|
self.udp = True
|
|
|
|
except:
|
2016-03-04 10:20:32 +01:00
|
|
|
self.udp = True
|
|
|
|
|
|
|
|
if not self.udp:
|
|
|
|
self.s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
|
|
|
|
self.dest = path
|
|
|
|
self.local = "/tmp/wpa_ctrl_" + str(os.getpid()) + '-' + str(counter)
|
|
|
|
counter += 1
|
|
|
|
self.s.bind(self.local)
|
|
|
|
try:
|
|
|
|
self.s.connect(self.dest)
|
2017-01-31 02:25:03 +01:00
|
|
|
except Exception as e:
|
2016-03-04 10:20:32 +01:00
|
|
|
self.s.close()
|
|
|
|
os.unlink(self.local)
|
|
|
|
raise
|
|
|
|
else:
|
|
|
|
try:
|
2016-05-19 15:06:47 +02:00
|
|
|
self.s = None
|
2016-03-04 10:20:32 +01:00
|
|
|
ai_list = socket.getaddrinfo(path, port, socket.AF_INET,
|
|
|
|
socket.SOCK_DGRAM)
|
|
|
|
for af, socktype, proto, cn, sockaddr in ai_list:
|
|
|
|
self.sockaddr = sockaddr
|
|
|
|
break
|
|
|
|
self.s = socket.socket(af, socktype)
|
|
|
|
self.s.settimeout(5)
|
2019-02-02 11:49:23 +01:00
|
|
|
self.s.sendto(b"GET_COOKIE", sockaddr)
|
2016-03-04 10:20:32 +01:00
|
|
|
reply, server = self.s.recvfrom(4096)
|
|
|
|
self.cookie = reply
|
|
|
|
self.port = port
|
|
|
|
except:
|
2017-01-31 02:25:03 +01:00
|
|
|
print("connect exception ", path, str(port))
|
2016-03-04 10:20:32 +01:00
|
|
|
if self.s != None:
|
|
|
|
self.s.close()
|
|
|
|
raise
|
2013-03-19 00:53:09 +01:00
|
|
|
self.started = True
|
|
|
|
|
|
|
|
def __del__(self):
|
|
|
|
self.close()
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
if self.attached:
|
2013-12-30 21:23:18 +01:00
|
|
|
try:
|
|
|
|
self.detach()
|
2017-01-31 02:25:03 +01:00
|
|
|
except Exception as e:
|
2013-12-30 21:23:18 +01:00
|
|
|
# Need to ignore this allow the socket to be closed
|
2014-04-28 14:31:25 +02:00
|
|
|
self.attached = False
|
2013-12-30 21:23:18 +01:00
|
|
|
pass
|
2013-03-19 00:53:09 +01:00
|
|
|
if self.started:
|
|
|
|
self.s.close()
|
2016-03-04 10:20:32 +01:00
|
|
|
if not self.udp:
|
|
|
|
os.unlink(self.local)
|
2013-03-19 00:53:09 +01:00
|
|
|
self.started = False
|
|
|
|
|
2014-03-12 10:42:59 +01:00
|
|
|
def request(self, cmd, timeout=10):
|
2019-02-02 11:49:23 +01:00
|
|
|
if type(cmd) == str:
|
|
|
|
try:
|
|
|
|
cmd2 = cmd.encode()
|
|
|
|
cmd = cmd2
|
|
|
|
except UnicodeDecodeError as e:
|
|
|
|
pass
|
2016-03-04 10:20:32 +01:00
|
|
|
if self.udp:
|
|
|
|
self.s.sendto(self.cookie + cmd, self.sockaddr)
|
|
|
|
else:
|
|
|
|
self.s.send(cmd)
|
2014-03-12 10:42:59 +01:00
|
|
|
[r, w, e] = select.select([self.s], [], [], timeout)
|
2013-03-19 00:53:09 +01:00
|
|
|
if r:
|
2019-02-02 11:49:23 +01:00
|
|
|
res = self.s.recv(4096).decode()
|
|
|
|
try:
|
|
|
|
r = str(res)
|
|
|
|
except UnicodeDecodeError as e:
|
|
|
|
r = res
|
|
|
|
return r
|
2013-03-19 00:53:09 +01:00
|
|
|
raise Exception("Timeout on waiting response")
|
|
|
|
|
|
|
|
def attach(self):
|
|
|
|
if self.attached:
|
|
|
|
return None
|
|
|
|
res = self.request("ATTACH")
|
|
|
|
if "OK" in res:
|
2013-12-30 21:23:18 +01:00
|
|
|
self.attached = True
|
2013-03-19 00:53:09 +01:00
|
|
|
return None
|
|
|
|
raise Exception("ATTACH failed")
|
|
|
|
|
|
|
|
def detach(self):
|
|
|
|
if not self.attached:
|
|
|
|
return None
|
2020-06-01 21:24:00 +02:00
|
|
|
if self.s.fileno() == -1:
|
|
|
|
self.attached = False
|
|
|
|
return None
|
2014-04-28 14:31:25 +02:00
|
|
|
while self.pending():
|
|
|
|
ev = self.recv()
|
2013-03-19 00:53:09 +01:00
|
|
|
res = self.request("DETACH")
|
2014-04-28 14:31:25 +02:00
|
|
|
if "FAIL" not in res:
|
2013-12-30 21:23:18 +01:00
|
|
|
self.attached = False
|
2013-03-19 00:53:09 +01:00
|
|
|
return None
|
|
|
|
raise Exception("DETACH failed")
|
|
|
|
|
2016-03-04 10:20:39 +01:00
|
|
|
def terminate(self):
|
|
|
|
if self.attached:
|
|
|
|
try:
|
|
|
|
self.detach()
|
2017-01-31 02:25:03 +01:00
|
|
|
except Exception as e:
|
2016-03-04 10:20:39 +01:00
|
|
|
# Need to ignore this to allow the socket to be closed
|
|
|
|
self.attached = False
|
|
|
|
self.request("TERMINATE")
|
|
|
|
self.close()
|
|
|
|
|
2014-01-05 07:46:45 +01:00
|
|
|
def pending(self, timeout=0):
|
|
|
|
[r, w, e] = select.select([self.s], [], [], timeout)
|
2013-03-19 00:53:09 +01:00
|
|
|
if r:
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def recv(self):
|
2019-02-02 11:49:23 +01:00
|
|
|
res = self.s.recv(4096).decode()
|
|
|
|
try:
|
|
|
|
r = str(res)
|
|
|
|
except UnicodeDecodeError as e:
|
|
|
|
r = res
|
|
|
|
return r
|