Skip to content

Commit

Permalink
Implemented support for setting the hostapd SSID accd to the AP Group…
Browse files Browse the repository at this point in the history
… SSID (#59, #60)

Note that this will only change the SSID on the AP when it's
 different than the value currently set on the AP, which should
 avoid connection thrashing.

The SSID can currently be over-written by putting an SSID
 value in the file specified by NETREACH_ADAPTER_SSID_OVERRIDE_FILE
 - currently "lib/netreach-ssid-override.txt".
  • Loading branch information
craigpratt authored Nov 13, 2021
1 parent 0dace86 commit e8c6ff1
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 5 deletions.
27 changes: 24 additions & 3 deletions micronets-gw-service/app/hostapd_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,7 @@ def read_cli_output(self):

async def process_hostapd_ready(self):
logger.info(f"HostapdAdapter:process_hostapd_ready()")
status_cmd = await self.send_command(HostapdAdapter.StatusCLICommand())
logger.info (f"HostapdAdapter:process_hostapd_ready: Retrieving status...")
self.status_vars = await status_cmd.get_status_dict()
await self.refresh_status_vars()
for handler in self.event_handler_table:
asyncio.ensure_future(handler.handle_hostapd_ready())

Expand All @@ -208,6 +206,11 @@ async def process_event(self, event_data):
if handler.event_prefixes is None or event_data.startswith(handler.event_prefixes):
asyncio.ensure_future(handler.handle_hostapd_cli_event(event_data))

async def refresh_status_vars(self):
logger.info(f"HostapdAdapter:refresh_status_vars()")
status_cmd = await self.send_command(HostapdAdapter.StatusCLICommand())
self.status_vars = await status_cmd.get_status_dict()

def get_status_var(self, var_name):
if not self.status_vars:
raise Exception("The Hostapd adapter status variables aren't initialized")
Expand Down Expand Up @@ -617,6 +620,24 @@ async def was_successful(self):
await self.get_response()
return self.success

class ReloadCLICommand(HostapdCLICommand):
def __init__ (self, event_loop=asyncio.get_event_loop()):
super().__init__(event_loop)
self.success = False

def get_command_string(self):
return "reload"

async def process_response_data(self, response):
try:
self.success = "OK" in response
finally:
await super().process_response_data(response)

async def was_successful(self):
await self.get_response()
return self.success

class ReloadPSKCLICommand(HostapdCLICommand):
def __init__ (self, event_loop=asyncio.get_event_loop()):
super().__init__(event_loop)
Expand Down
32 changes: 30 additions & 2 deletions micronets-gw-service/app/netreach_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ def __init__ (self, config):
self.pub_key_file = config['NETREACH_ADAPTER_PUBLIC_KEY_FILE']
self.priv_key_file = config['NETREACH_ADAPTER_PRIVATE_KEY_FILE']
self.wifi_interface = config['NETREACH_ADAPTER_WIFI_INTERFACE']
self.ssid_override_file = config['NETREACH_ADAPTER_SSID_OVERRIDE_FILE']
self.unassigned_ssid = config['NETREACH_ADAPTER_UNASSIGNED_SSID']
self.geolocation = config.get('NETREACH_ADAPTER_GEOLOCATION')
self.management_address = config.get('NETREACH_ADAPTER_MAN_ADDRESS')
self.management_interface = config.get('NETREACH_ADAPTER_MAN_INTERFACE')
Expand Down Expand Up @@ -60,6 +62,7 @@ def __init__ (self, config):
if not self.management_address and self.management_interface:
logger.info(f"NetreachAdapter: Setting management address to {self.management_interface} address")
self.management_address = self._ip_for_interface(self.management_interface)
self.ssid_override = self.ssid_override_file.read_text().strip() if self.ssid_override_file.exists() else None
if not self.geolocation:
self.geolocation = self._get_geolocation()
self.pub_key = None
Expand Down Expand Up @@ -310,6 +313,7 @@ async def _setup_micronets_for_ap(self):
ap_groups = result.json()['results']
if len(ap_groups) == 0:
logger.info(f"NetreachAdapter:_setup_micronets_for_ap {self.ap_name} ({self.ap_uuid}) does not have an AP Group. Nothing to setup.")
await self._configure_ap_for_ssids([self.unassigned_ssid])
return
ap_group = ap_groups[0]

Expand All @@ -320,7 +324,8 @@ async def _setup_micronets_for_ap(self):
logger.info(f"NetreachAdapter:_setup_micronets_for_ap: apGroup {self.ap_group_name} "
f"(apGroup {self.ap_group_uuid})")
logger.info(f"NetreachAdapter:_setup_micronets_for_ap: ssid(s) {self.ssid_list}")
# TODO: Configure hostapd with the given ssid(s)
await self._configure_ap_for_ssids(self.ssid_list if not self.ssid_override else [self.ssid_override])

result = httpx.get(f"{self.controller_base_url}/v1/services/?apGroupUuid={self.ap_group_uuid}",
headers={"x-api-token": self.api_token})
if result.is_error:
Expand All @@ -337,7 +342,7 @@ async def _setup_micronets_for_ap(self):
micronet_subnet = IPv4Network(service['micronetSubnet'], strict=True)
micronet_vlan = int(service['vlan'])
# TODO: Replace this with gateway reference from Service object (see issue #15)
micronet_gateway = str(next(micronet_subnet.hosts()))
micronet_gateway = service['micronetGateway']
logger.info(f"NetreachAdapter:_setup_micronets_for_ap: Found service {service_name} ({service_uuid})")
logger.info(f"NetreachAdapter:_setup_micronets_for_ap: micronet id {service_uuid} vlan {micronet_vlan}")
if not (micronet_subnet and micronet_vlan):
Expand Down Expand Up @@ -414,6 +419,29 @@ async def _setup_micronets_for_ap(self):
f"for service {service_name} ({service_uuid}) - Result was {result.reason_phrase}")
continue

async def _configure_ap_for_ssids(self, ssids):
# Note: This only deals with one SSID currently
logger.info(f"NetreachAdapter:_configure_ap_for_ssids({ssids})")
ssid = ssids[0]

cur_ssids = self.hostapd_adapter.get_status_var("ssid")
if cur_ssids[0] == ssid:
logger.info(f"NetreachAdapter:_configure_ap_for_ssids({ssids}): AP SSID already set to \"{ssid}\" "
f"- nothing to do")
return

logger.info(f"NetreachAdapter:_configure_ap_for_ssids({ssids}): Changing AP SSID from \"{cur_ssids[0]}\" "
f"to \"{ssid}\"")
set_cmd = await self.hostapd_adapter.send_command(HostapdAdapter.SetCLICommand("ssid", ssid))
if not await set_cmd.was_successful():
response = await set_cmd.get_response()
raise Exception(f"Could not set ssid to {ssid}: {response}")

reload_cmd = await self.hostapd_adapter.send_command(HostapdAdapter.ReloadCLICommand())
if not await reload_cmd.was_successful():
raise Exception(f"Error issuing hostapd reload after setting SSID to {ssid}")
await self.hostapd_adapter.refresh_status_vars()

def _on_mqtt_connect(self, client, userdata, flags, rc):
# handles the connecting event of the mqtt broker
logger.info(f"NetreachAdapter:_on_mqtt_connect(client:{client},userdata:{userdata},flags:{flags},rc:{rc})")
Expand Down
2 changes: 2 additions & 0 deletions micronets-gw-service/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class NetreachDefaultSettings():
NETREACH_ADAPTER_MAN_INTERFACE = "eth0"
# NETREACH_ADAPTER_MAN_ADDRESS = "1.2.3.4"
# NETREACH_ADAPTER_GEOLOCATION = {"latitude": "0.0", "longitude": "0.0"}
NETREACH_ADAPTER_SSID_OVERRIDE_FILE = libpath.joinpath('netreach-ssid-override.txt')
NETREACH_ADAPTER_UNASSIGNED_SSID = "netreach-inactive"
NETREACH_ADAPTER_CONTROLLER_BASE_URL = "https://staging.api.controller.netreach.in"
NETREACH_ADAPTER_API_KEY_FILE = libpath.joinpath('netreach-api-token.txt')
NETREACH_ADAPTER_API_KEY_REFRESH_DAYS = 500
Expand Down

0 comments on commit e8c6ff1

Please # to comment.