Remove use of iw and hostapd.

pull/535/head
connor rigby 2018-05-11 13:04:12 -07:00 committed by Connor Rigby
parent ad30f27945
commit acd3f2324d
11 changed files with 165 additions and 234 deletions

1
.gitignore vendored
View File

@ -14,6 +14,7 @@ ttb_last_config
/nerves/*
!/nerves/host
!/nerves/target
_nerves_tmp
# Secret config
auth_secret_test.exs

View File

@ -25,7 +25,6 @@ defmodule Farmbot do
end
def init([]) do
Logger.remove_backend :console
RingLogger.attach()
children = [
{Farmbot.Logger.Supervisor, []},

View File

@ -75,6 +75,7 @@ defmodule Farmbot.System.Init.Ecto do
migrated = migrator.(repo, migrations_path, :up, opts)
pid && repo.stop(pid)
Mix.Ecto.restart_apps_if_migrated(apps, migrated)
Logger.remove_backend Logger.Backends.Console
Process.sleep(500)
end
end

View File

@ -142,7 +142,8 @@ defmodule Farmbot.Mixfile do
{:nerves_runtime, "0.5.3"},
{:nerves_firmware, "~> 0.4.0"},
{:nerves_init_gadget, "~> 0.3.0", only: :dev},
{:nerves_network, "~> 0.3.7-rc0", override: true},
{:nerves_network, "~> 0.3"},
{:nerves_wpa_supplicant, github: "nerves-project/nerves_wpa_supplicant", override: true},
{:dhcp_server, "~> 0.3.0"},
{:elixir_ale, "~> 1.0"},
{:mdns, "~> 1.0"},

View File

@ -38,7 +38,7 @@
"nerves_firmware_ssh": {:hex, :nerves_firmware_ssh, "0.3.1", "e8b1967fa0aff255230be539c68ec868d33884193a385caff957ebad7d6aa8af", [:mix], [{:nerves_runtime, "~> 0.4", [hex: :nerves_runtime, repo: "hexpm", optional: false]}], "hexpm"},
"nerves_init_gadget": {:hex, :nerves_init_gadget, "0.3.0", "4c8fdd6af9f9ad82763d7e93ab1a3f380f64d4b2804cf70acad907261b7b16be", [:mix], [{:mdns, "~> 1.0", [hex: :mdns, repo: "hexpm", optional: false]}, {:nerves_firmware_ssh, "~> 0.2", [hex: :nerves_firmware_ssh, repo: "hexpm", optional: false]}, {:nerves_network, "~> 0.3", [hex: :nerves_network, repo: "hexpm", optional: false]}, {:nerves_runtime, "~> 0.3", [hex: :nerves_runtime, repo: "hexpm", optional: false]}, {:ring_logger, "~> 0.4", [hex: :ring_logger, repo: "hexpm", optional: false]}], "hexpm"},
"nerves_leds": {:hex, :nerves_leds, "0.8.0", "193692767dca1a201b09113d242648493b9be0087bab83ebee99c3b0a254f5e1", [:mix], [], "hexpm"},
"nerves_network": {:hex, :nerves_network, "0.3.7-rc0", "83d2967c6e90c9b2b740312885cb890bfd7a9e9025feee1464b768577b1fb28b", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nerves_network_interface, "~> 0.4.4", [hex: :nerves_network_interface, repo: "hexpm", optional: false]}, {:nerves_wpa_supplicant, "~> 0.3.2", [hex: :nerves_wpa_supplicant, repo: "hexpm", optional: false]}, {:system_registry, "~> 0.7", [hex: :system_registry, repo: "hexpm", optional: false]}], "hexpm"},
"nerves_network": {:hex, :nerves_network, "0.3.6", "c95779283ace071e9d12882d6a80e31edc8c476012adc61aba2ff6c306ef97b3", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:nerves_network_interface, "~> 0.4.0", [hex: :nerves_network_interface, repo: "hexpm", optional: false]}, {:nerves_wpa_supplicant, "~> 0.3.0", [hex: :nerves_wpa_supplicant, repo: "hexpm", optional: false]}, {:system_registry, "~> 0.4", [hex: :system_registry, repo: "hexpm", optional: false]}], "hexpm"},
"nerves_network_interface": {:hex, :nerves_network_interface, "0.4.4", "200b1a84bc1a7fdeaf3a1e0e2d4e9b33e240b034e73f39372768d43f8690bae0", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"nerves_runtime": {:hex, :nerves_runtime, "0.5.3", "7447a3e718762f3901046f72cc824e528f8d0565a581b8ae58f4f5b6436bca7f", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:system_registry, "~> 0.5", [hex: :system_registry, repo: "hexpm", optional: false]}], "hexpm"},
"nerves_system_br": {:hex, :nerves_system_br, "1.0.1", "ca3b6f3c9bad0eadbeef7567a83dbbd87208e290edb2377ff9932609e3806c30", [:mix], [], "hexpm"},
@ -47,7 +47,7 @@
"nerves_toolchain_arm_unknown_linux_gnueabihf": {:hex, :nerves_toolchain_arm_unknown_linux_gnueabihf, "1.0.0", "39da5b503b977a594c9e386ca16a50c433b333797bc30ac941fd402ce1832274", [:mix], [{:nerves, "~> 1.0", [hex: :nerves, repo: "hexpm", optional: false]}, {:nerves_toolchain_ctng, "~> 1.4", [hex: :nerves_toolchain_ctng, repo: "hexpm", optional: false]}], "hexpm"},
"nerves_toolchain_ctng": {:hex, :nerves_toolchain_ctng, "1.4.0", "ec844dd286a5281223e023edb1359c8763fef79a3af9daac45397713cff1cb88", [:mix], [{:nerves, "~> 1.0", [hex: :nerves, repo: "hexpm", optional: false]}], "hexpm"},
"nerves_uart": {:hex, :nerves_uart, "1.1.1", "2ba6282b45513268249e78880cd84bc37c5758ee7db9c6d92f442be21fcacc35", [:mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"nerves_wpa_supplicant": {:hex, :nerves_wpa_supplicant, "0.3.2", "19dc7e1248336e7f542b11b2b857ceb5b088d3eb41a6ca75b7b76628dcf67aad", [:make, :mix], [{:elixir_make, "~> 0.3", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm"},
"nerves_wpa_supplicant": {:git, "https://github.com/nerves-project/nerves_wpa_supplicant.git", "2b3bb056a1594bff16b44d37876e8d599349dcb5", []},
"phoenix_html": {:hex, :phoenix_html, "2.10.5", "4f9df6b0fb7422a9440a73182a566cb9cbe0e3ffe8884ef9337ccf284fc1ef0a", [:mix], [{:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"plug": {:hex, :plug, "1.4.5", "7b13869283fff6b8b21b84b8735326cc012c5eef8607095dc6ee24bd0a273d8e", [:mix], [{:cowboy, "~> 1.0.1 or ~> 1.1", [hex: :cowboy, repo: "hexpm", optional: true]}, {:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
@ -64,7 +64,7 @@
"sqlite_ecto2": {:hex, :sqlite_ecto2, "2.2.2", "7a3e5c0521e1cb6e30a4907ba4d952b97db9b2ab5d1a4806ceeb66a10b23ba65", [:mix], [{:connection, "~> 1.0.3", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1.0", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 2.2.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:esqlite, "~> 0.2.3", [hex: :esqlite, repo: "hexpm", optional: false]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: false]}, {:sqlitex, "~> 1.3.2 or ~> 1.4", [hex: :sqlitex, repo: "hexpm", optional: false]}], "hexpm"},
"sqlitex": {:hex, :sqlitex, "1.3.3", "3aac5fd702be346f71d9de6e01702c9954484cd0971aa443490bb3bde045d919", [:mix], [{:decimal, "~> 1.1", [hex: :decimal, repo: "hexpm", optional: false]}, {:esqlite, "~> 0.2.3", [hex: :esqlite, repo: "hexpm", optional: false]}], "hexpm"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], [], "hexpm"},
"system_registry": {:hex, :system_registry, "0.7.0", "cd3aaf2c15392fa60f93869dde49f536fcf60e54f3b15db737e7d4ebcac108f4", [:mix], [], "hexpm"},
"system_registry": {:hex, :system_registry, "0.8.0", "09240347628b001433d18279a2759ef7237ba7361239890d8c599cca9a2fbbc2", [:mix], [], "hexpm"},
"timex": {:hex, :timex, "3.2.1", "639975eac45c4c08c2dbf7fc53033c313ff1f94fad9282af03619a3826493612", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:gettext, "~> 0.10", [hex: :gettext, repo: "hexpm", optional: false]}, {:tzdata, "~> 0.1.8 or ~> 0.5", [hex: :tzdata, repo: "hexpm", optional: false]}], "hexpm"},
"tzdata": {:hex, :tzdata, "0.5.16", "13424d3afc76c68ff607f2df966c0ab4f3258859bbe3c979c9ed1606135e7352", [:mix], [{:hackney, "~> 1.0", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.3.1", "a1f612a7b512638634a603c8f401892afbf99b8ce93a45041f8aaca99cadb85e", [:rebar3], [], "hexpm"},

View File

@ -4,13 +4,37 @@ defmodule Farmbot.Target.Bootstrap.Configurator.CaptivePortal do
@interface Application.get_env(:farmbot, :captive_portal_interface, "wlan0")
@address Application.get_env(:farmbot, :captive_portal_address, "192.168.25.1")
@dnsmasq_conf_file "dnsmasq.conf"
@dnsmasq_pid_file "dnsmasq.pid"
def start_link() do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def init([]) do
Logger.busy(3, "Starting captive portal.")
{:ok, hostapd} = Hostapd.start_link(interface: @interface, address: @address)
ensure_interface(@interface)
Nerves.Network.teardown(@interface)
host_ap_opts = [
ssid: build_ssid(),
key_mgmt: :NONE,
mode: 2,
# ap_scan: 0,
# scan_ssid: 1,
]
Nerves.Network.setup(@interface, host_ap_opts)
ip_opts = [
ipv4_address_method: :static,
ipv4_address: @address, ipv4_subnet_mask: "255.255.0.0",
nameservers: [@address]
]
Nerves.NetworkInterface.setup(@interface, ip_opts)
dhcp_opts = [
gateway: @address,
netmask: "255.255.255.0",
@ -18,15 +42,32 @@ defmodule Farmbot.Target.Bootstrap.Configurator.CaptivePortal do
domain_servers: [@address],
]
{:ok, dhcp_server} = DHCPServer.start_link(@interface, dhcp_opts)
{:ok, %{hostapd: hostapd, dhcp_server: dhcp_server}}
dnsmasq = setup_dnsmasq(@address, @interface)
wpa_pid = wait_for_wpa()
Nerves.WpaSupplicant.request(wpa_pid, {:AP_SCAN, 2})
{:ok, %{dhcp_server: dhcp_server, dnsmasq: dnsmasq}}
end
defp wait_for_wpa do
name = :"Nerves.WpaSupplicant.#{@interface}"
GenServer.whereis(name) || wait_for_wpa()
end
def terminate(_, state) do
Logger.busy 3, "Stopping captive portal GenServer."
Logger.busy 3, "Stopping DHCP GenServer."
GenServer.stop(state.dhcp_server, :normal)
Logger.busy 3, "Stopping Hostapd GenServer."
GenServer.stop(state.hostapd, :normal)
stop_dnsmasq(state)
Nerves.Network.teardown(@interface)
end
def handle_info({_port, {:data, _data}}, state) do
{:noreply, state}
end
defp dhcp_range_begin(address) do
@ -38,4 +79,77 @@ defmodule Farmbot.Target.Bootstrap.Configurator.CaptivePortal do
[a, b, c, _] = String.split(address, ".")
Enum.join([a, b, c, "10"], ".")
end
defp ensure_interface(interface) do
unless interface in Nerves.NetworkInterface.interfaces() do
Logger.debug 2, "Waiting for #{interface}: #{inspect Nerves.NetworkInterface.interfaces()}"
Process.sleep(100)
ensure_interface(interface)
end
end
defp build_ssid do
node_str = node() |> Atom.to_string()
case node_str |> String.split("@") do
[name, "farmbot-" <> id] -> name <> "-" <> id
_ -> "Farmbot"
end
end
defp setup_dnsmasq(ip_addr, interface) do
dnsmasq_conf = build_dnsmasq_conf(ip_addr, interface)
File.mkdir!("/tmp/dnsmasq")
:ok = File.write("/tmp/dnsmasq/#{@dnsmasq_conf_file}", dnsmasq_conf)
dnsmasq_cmd = "dnsmasq -k --dhcp-lease " <>
"/tmp/dnsmasq/#{@dnsmasq_pid_file} " <>
"--conf-dir=/tmp/dnsmasq"
dnsmasq_port = Port.open({:spawn, dnsmasq_cmd}, [:binary])
dnsmasq_os_pid = dnsmasq_port|> Port.info() |> Keyword.get(:os_pid)
{dnsmasq_port, dnsmasq_os_pid}
end
defp build_dnsmasq_conf(ip_addr, interface) do
"""
interface=#{interface}
address=/#/#{ip_addr}
server=/farmbot/#{ip_addr}
local=/farmbot/
domain=farmbot
"""
end
defp stop_dnsmasq(state) do
case state.dnsmasq do
{dnsmasq_port, dnsmasq_os_pid} ->
Logger.busy 3, "Stopping dnsmasq"
Logger.busy 3, "Killing dnsmasq PID."
:ok = kill(dnsmasq_os_pid)
Port.close(dnsmasq_port)
Logger.success 3, "Stopped dnsmasq."
:ok
_ ->
Logger.debug 3, "Dnsmasq not running."
:ok
end
rescue
e ->
Logger.error 3, "Error stopping dnsmasq: #{Exception.message(e)}"
:ok
end
defp kill(os_pid), do: :ok = cmd("kill -9 #{os_pid}")
defp cmd(cmd_str) do
[command | args] = String.split(cmd_str, " ")
System.cmd(command, args, into: IO.stream(:stdio, :line))
|> print_cmd()
end
defp print_cmd({_, 0}), do: :ok
defp print_cmd({_, num}) do
Logger.error(2, "Encountered an error (#{num})")
:error
end
end

View File

@ -1,218 +0,0 @@
defmodule Hostapd do
@moduledoc """
Manages an OS process of hostapd.
"""
defmodule State do
@moduledoc false
defstruct [:hostapd, :dnsmasq, :interface, :ip_addr]
end
use GenServer
use Farmbot.Logger
@hostapd_conf_file "hostapd.conf"
@hostapd_pid_file "hostapd.pid"
@dnsmasq_conf_file "dnsmasq.conf"
@dnsmasq_pid_file "dnsmasq.pid"
defp ensure_interface(interface) do
unless interface in Nerves.NetworkInterface.interfaces() do
Logger.debug 2, "Waiting for #{interface}: #{inspect Nerves.NetworkInterface.interfaces()}"
Process.sleep(100)
ensure_interface(interface)
end
end
@doc false
def start_link(opts, gen_server_opts \\ []) do
GenServer.start_link(__MODULE__, opts, gen_server_opts)
end
def init(opts) do
# We want to know if something does.
Process.flag(:trap_exit, true)
interface = Keyword.fetch!(opts, :interface)
address = Keyword.fetch!(opts, :address)
Logger.busy(3, "Starting hostapd on #{interface}")
ensure_interface(interface)
dnsmasq_path = System.find_executable("dnsmasq")
dnsmasq_settings = if dnsmasq_path do
setup_dnsmasq(address, interface)
else
nil
end
{hostapd_port, hostapd_os_pid} = setup_hostapd(interface, address)
state = %State{
hostapd: {hostapd_port, hostapd_os_pid},
dnsmasq: dnsmasq_settings,
interface: interface,
ip_addr: address
}
{:ok, state}
end
defp setup_dnsmasq(ip_addr, interface) do
dnsmasq_conf = build_dnsmasq_conf(ip_addr, interface)
File.mkdir!("/tmp/dnsmasq")
:ok = File.write("/tmp/dnsmasq/#{@dnsmasq_conf_file}", dnsmasq_conf)
dnsmasq_cmd = "dnsmasq -k --dhcp-lease " <>
"/tmp/dnsmasq/#{@dnsmasq_pid_file} " <>
"--conf-dir=/tmp/dnsmasq"
dnsmasq_port = Port.open({:spawn, dnsmasq_cmd}, [:binary])
dnsmasq_os_pid = dnsmasq_port|> Port.info() |> Keyword.get(:os_pid)
{dnsmasq_port, dnsmasq_os_pid}
end
defp build_dnsmasq_conf(ip_addr, interface) do
"""
interface=#{interface}
address=/#/#{ip_addr}
server=/farmbot/#{ip_addr}
local=/farmbot/
domain=farmbot
"""
end
defp setup_hostapd(interface, ip_addr) do
# Make sure the interface is in proper condition.
:ok = hostapd_ip_settings_up(interface, ip_addr)
# build the hostapd configuration
hostapd_conf = build_hostapd_conf(interface, build_ssid())
# build a config file
File.mkdir!("/tmp/hostapd")
File.write!("/tmp/hostapd/#{@hostapd_conf_file}", hostapd_conf)
hostapd_cmd =
"hostapd -P /tmp/hostapd/#{@hostapd_pid_file} "
<> "/tmp/hostapd/#{@hostapd_conf_file}"
hostapd_port = Port.open({:spawn, hostapd_cmd}, [:binary])
hostapd_os_pid = hostapd_port |> Port.info() |> Keyword.get(:os_pid)
{hostapd_port, hostapd_os_pid}
end
defp hostapd_ip_settings_up(interface, ip_addr) do
:ok = cmd("ip link set #{interface} up")
:ok = cmd("ip addr add #{ip_addr}/24 dev #{interface}")
:ok
end
defp hostapd_ip_settings_down(interface, ip_addr) do
:ok = cmd("ip link set #{interface} down")
:ok = cmd("ip addr del #{ip_addr}/24 dev #{interface}")
:ok = cmd("ip link set #{interface} up")
:ok
end
defp build_hostapd_conf(interface, ssid) do
"""
interface=#{interface}
ssid=#{ssid}
hw_mode=g
channel=6
auth_algs=1
wmm_enabled=0
"""
end
defp build_ssid do
node_str = node() |> Atom.to_string()
case node_str |> String.split("@") do
[name, "farmbot-" <> id] -> name <> "-" <> id
_ -> "Farmbot"
end
end
def handle_info({port, {:data, data}}, state) do
{hostapd_port, _} = state.hostapd
cond do
port == hostapd_port -> handle_hostapd(data, state)
match?({^port, _}, state.dnsmasq) -> handle_dnsmasq(data, state)
true -> {:noreply, state}
end
end
def handle_info(_, state), do: {:noreply, state}
defp handle_hostapd(data, state) when is_bitstring(data) do
Logger.debug(3, String.trim(data))
{:noreply, state}
end
defp handle_dnsmasq(data, state) when is_bitstring(data) do
Logger.debug(3, String.trim(data))
{:noreply, state}
end
defp stop_hostapd(state) do
case state.hostapd do
{hostapd_port, hostapd_pid} ->
Logger.busy 3, "Stopping hostapd"
Logger.busy 3, "Killing hostapd PID."
:ok = kill(hostapd_pid)
Port.close(hostapd_port)
Logger.busy 3, "Resetting ip settings."
hostapd_ip_settings_down(state.interface, state.ip_addr)
Logger.busy 3, "removing PID."
File.rm_rf!("/tmp/hostapd")
Logger.success 3, "Stopped hostapd."
:ok
_ ->
Logger.debug 3, "Hostapd not running."
:ok
end
rescue
e ->
Logger.error 3, "Error stopping hostapd: #{Exception.message(e)}"
:ok
end
defp stop_dnsmasq(state) do
case state.dnsmasq do
{dnsmasq_port, dnsmasq_os_pid} ->
Logger.busy 3, "Stopping dnsmasq"
Logger.busy 3, "Killing dnsmasq PID."
:ok = kill(dnsmasq_os_pid)
Port.close(dnsmasq_port)
Logger.success 3, "Stopped dnsmasq."
:ok
_ ->
Logger.debug 3, "Dnsmasq not running."
:ok
end
rescue
e ->
Logger.error 3, "Error stopping dnsmasq: #{Exception.message(e)}"
:ok
end
def terminate(_, state) do
stop_hostapd(state)
stop_dnsmasq(state)
Nerves.NetworkInterface.ifdown(state.interface)
Nerves.NetworkInterface.ifup(state.interface)
end
defp kill(os_pid), do: :ok = cmd("kill -9 #{os_pid}")
defp cmd(cmd_str) do
[command | args] = String.split(cmd_str, " ")
System.cmd(command, args, into: IO.stream(:stdio, :line))
|> print_cmd()
end
defp print_cmd({_, 0}), do: :ok
defp print_cmd({_, num}) do
Logger.error(2, "Encountered an error (#{num})")
:error
end
end

View File

@ -7,6 +7,7 @@ defmodule Farmbot.Target.Bootstrap.Configurator do
@behaviour Farmbot.System.Init
use Farmbot.Logger
alias Farmbot.System.ConfigStorage
alias Farmbot.Target.Bootstrap.Configurator
@doc """
This particular init module should block until all settings have been validated.
@ -48,11 +49,10 @@ defmodule Farmbot.Target.Bootstrap.Configurator do
import Supervisor.Spec
:ets.new(:session, [:named_table, :public, read_concurrency: true])
Farmbot.System.GPIO.Leds.led_status_err()
alias Farmbot.Target.Bootstrap.Configurator
ConfigStorage.destroy_all_network_configs()
children = [
{Plug.Adapters.Cowboy, scheme: :http, plug: Configurator.Router, options: [port: 80, acceptors: 1]},
worker(Configurator.CaptivePortal, [])
worker(Configurator.CaptivePortal, []),
{Plug.Adapters.Cowboy, scheme: :http, plug: Configurator.Router, options: [port: 80, acceptors: 1]}
]
opts = [strategy: :one_for_one]

View File

@ -70,7 +70,7 @@ defmodule Farmbot.Target.Bootstrap.Configurator.Router do
get "/config_wireless" do
try do
ifname = conn.params["ifname"] || raise(MissingField, field: "ifname", message: "ifname not provided", redir: "/network")
opts = [ifname: ifname, ssids: Farmbot.Target.Network.do_scan(ifname), post_action: "config_wireless_step_1"]
opts = [ifname: ifname, ssids: Farmbot.Target.Network.scan(ifname), post_action: "config_wireless_step_1"]
render_page(conn, "/config_wireless_step_1", opts)
rescue
e in MissingField -> redir(conn, e.redir)

View File

@ -15,7 +15,6 @@ defmodule Farmbot.Target.Network.Manager do
end
def init({interface, opts} = args) do
Elixir.Logger.remove_backend Elixir.Logger.Backends.Console
Logger.busy(3, "Waiting for interface #{interface} up.")
unless interface in Nerves.NetworkInterface.interfaces() do
@ -24,6 +23,8 @@ defmodule Farmbot.Target.Network.Manager do
end
Logger.success(3, "Interface #{interface} is up.")
Nerves.Network.teardown("wlan0")
SystemRegistry.register()
{:ok, _} = Elixir.Registry.register(Nerves.NetworkInterface, interface, [])
{:ok, _} = Elixir.Registry.register(Nerves.Udhcpc, interface, [])

View File

@ -32,8 +32,8 @@ defmodule Farmbot.Target.Network do
end
@doc "Scan on an interface. "
def do_scan(iface) do
Nerves.Network.scan(iface)
def scan(iface) do
do_scan(iface)
|> ScanResult.decode()
|> ScanResult.sort_results()
|> ScanResult.decode_security()
@ -41,6 +41,38 @@ defmodule Farmbot.Target.Network do
|> Enum.map(&Map.update(&1, :ssid, nil, fn(ssid) -> to_string(ssid) end))
|> Enum.reject(&String.contains?(&1.ssid, "\\x00"))
|> Enum.uniq_by(fn(%{ssid: ssid}) -> ssid end)
end
# While scanning in AP mode, The CTRL-EVENT-SCAN-COMPLETE event never happens.
defp wait_for_scan_results(pid, timer, count, loops_without_change, acc)
defp wait_for_scan_results(_pid, _timer, _count, 10, acc), do: acc
defp wait_for_scan_results(pid, timer, count, loops_without_change, acc) do
res = Nerves.WpaSupplicant.request(pid, {:BSS, count})
new_acc = if res, do: [res | acc], else: acc
new_count = if res, do: count + 1, else: count
new_loops_without_change = if res, do: 0, else: loops_without_change + 1
receive do
:complete -> acc
{Nerves.WpaSupplicant, {:"CTRL-EVENT-BSS-REMOVED", _, _}, _} ->
Process.cancel_timer(timer)
wait_for_scan_results(pid, Process.send_after(self(), :complete, 5000), 0, 0, [])
_ -> wait_for_scan_results(pid, timer, new_count, new_loops_without_change, new_acc)
after 10 -> wait_for_scan_results(pid, timer, new_count, new_loops_without_change, new_acc)
end
end
def do_scan(iface) do
pid = :"Nerves.WpaSupplicant.#{iface}"
Elixir.Registry.register(Nerves.WpaSupplicant, iface, [])
case Nerves.WpaSupplicant.request(pid, :SCAN) do
r when r in ["FAIL-BUSY", :ok] ->
results = wait_for_scan_results(pid, Process.send_after(self(), :complete, 5000), 0, 0, [])
Elixir.Registry.unregister(Nerves.WpaSupplicant, iface)
results
resp -> raise("Unexpected scan result: #{inspect resp}")
end
end
@doc "Tests if we can make dns queries."