jfcloutier / vintage_net_wifi

WiFi networking for VintageNet

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

vintage net logo

Hex version API docs CircleCI Coverage Status

VintageNetWiFi makes it easy to add WiFi support for your device. This can be as simple as connecting to a WiFi access point or starting a WiFi access point so that other computers can connect directly.

You will need a WiFi module to use this library. If you're using Nerves, the official Raspberry Pi and Beaglebone systems contain WiFi drivers for built-in modules. If you are using a USB WiFi module, make sure that the Linux device driver for that module is loaded and any required firmware is available.

Once that's done, all that you need to do is add :vintage_net_wifi to your mix dependencies like this:

def deps do
  [
    {:vintage_net_wifi, "~> 0.9.0", targets: @all_targets}
  ]
end

VintageNetWiFi also requires that the wpa_supplicant package and necessary WiFi kernel modules are included in the system. All officially supported Nerves systems that run on hardware with WiFI should work.

In Buildroot, check that BR2_PACKAGE_WPA_SUPPLICANT is enabled.

If you are using access point mode, check that CONFIG_UDHCPD is enabled in Busybox and BR2_PACKAGE_WPA_SUPPLICANT_HOTSPOT is enabled in Buildroot.

WiFi network interfaces typically have names like "wlan0" or "wlan1" when using Nerves. Most of the time, there's only one WiFi interface and its "wlan0". Some WiFi adapters expose separate interfaces for 2.4 GHz and 5 GHz and they can be configured independently.

An example WiFi configuration looks like this:

config :vintage_net,
  config: [
    {"wlan0",
      %{
        type: VintageNetWiFi,
        vintage_net_wifi: %{
          networks: [
            %{
              key_mgmt: :wpa_psk,
              ssid: "my_network_ssid",
              psk: "a_passphrase_or_psk",
            }
          ]
        },
        ipv4: %{method: :dhcp},
      }
    }
  ]

The :ipv4 key is handled by vintage_net to set the IP address on the connection. Most of the time, you'll want to use DHCP to dynamically get an IP address.

The :vintage_net_wifi key has the following common fields:

  • :ap_scan - See wpa_supplicant documentation. The default for this, 1, should work for nearly all users.
  • :bgscan - Periodic background scanning to support roaming within an ESS.
    • :simple
    • {:simple, args} - args is a string to be passed to the simple wpa module
    • :learn
    • {:learn, args} args is a string to be passed to the learn wpa module
  • :passive_scan
    • 0: Do normal scans (allow active scans) (default)
    • 1: Do passive scans.
  • :regulatory_domain: Two character country code. Technology configuration will take priority over Application configuration
  • :networks - A list of Wi-Fi networks to configure. In client mode, VintageNet connects to the first available network in the list. In host mode, the list should have one entry with SSID and password information.
    • :mode -
      • :infrastructure (default) - Normal operation. Associate with an AP
      • :ap - access point mode
      • :ibss - peer to peer mode (not supported)
      • :p2p_go - P2P Go mode (not supported)
      • :p2p_group_formation - P2P Group Formation mode (not supported)
      • :mesh - mesh mode
    • :ssid - The SSID for the network
    • :key_mgmt - WiFi security mode (:wpa_psk for WPA2, :none for no password or WEP)
    • :psk - A WPA2 passphrase or the raw PSK. If a passphrase is passed in, it will be converted to a PSK and discarded.
    • :priority - The priority to set for a network if you are using multiple network configurations
    • :scan_ssid - Scan with SSID-specific Probe Request frames (this can be used to find APs that do not accept broadcast SSID or use multiple SSIDs; this will add latency to scanning, so enable this only when needed)
    • :frequency - When in :ibss mode, use this channel frequency (in MHz). For example, specify 2412 for channel 1.

See the official docs for the complete list of options.

Here's an example:

iex> VintageNet.configure("wlan0", %{
      type: VintageNetWiFi,
      vintage_net_wifi: %{
        networks: [
          %{
            key_mgmt: :wpa_psk,
            psk: "a_passphrase_or_psk",
            ssid: "my_network_ssid"
          }
        ]
      },
      ipv4: %{method: :dhcp}
    })

Example of WEP:

iex> VintageNet.configure("wlan0", %{
      type: VintageNetWiFi,
      vintage_net_wifi: %{
        networks: [
          %{
            ssid: "my_network_ssid",
            wep_key0: "42FEEDDEAFBABEDEAFBEEFAA55",
            key_mgmt: :none,
            wep_tx_keyidx: 0
          }
        ]
      },
      ipv4: %{method: :dhcp}
    })

Enterprise Wi-Fi (WPA-EAP) support mostly passes through to the wpa_supplicant. Instructions for enterprise network for Linux should map. For example:

iex> VintageNet.configure("wlan0", %{
      type: VintageNetWiFi,
      vintage_net_wifi: %{
        networks: [
          %{
            ssid: "testing",
            key_mgmt: :wpa_eap,
            pairwise: "CCMP TKIP",
            group: "CCMP TKIP",
            eap: "PEAP",
            identity: "user1",
            password: "supersecret",
            phase1: "peapver=auto",
            phase2: "MSCHAPV2"
          }
        ]
      },
      ipv4: %{method: :dhcp}
})

Network adapters that can run as an Access Point can be configured as follows:

iex> VintageNet.configure("wlan0", %{
      type: VintageNetWiFi,
      vintage_net_wifi: %{
        networks: [
          %{
            mode: :ap,
            ssid: "test ssid",
            key_mgmt: :none
          }
        ]
      },
      ipv4: %{
        method: :static,
        address: "192.168.24.1",
        gateway: "192.168.24.255",
        netmask: "255.255.255.0",
        name_servers: ["1.1.1.1"]
      },
      dhcpd: %{
        start: "192.168.24.2",
        end: "192.168.24.10"
      }
})

If your device may be installed in different countries, you should override the default regulatory domain to the desired country at runtime. VintageNet uses the global domain by default and that will restrict the set of available WiFi frequencies in some countries. For example:

iex> VintageNet.configure("wlan0", %{
      type: VintageNetWiFi,
      vintage_net_wifi: %{
        regulatory_domain: "US",
        networks: [
          %{
            ssid: "testing",
            key_mgmt: :wpa_psk,
            psk: "super secret"
          }
        ]
      },
      ipv4: %{method: :dhcp}
})

Network adapters that can be configured to support 80211s mesh networking can be configured as follows:

(Raspberry Pi internal WiFi modules do not support 80211s meshing)

VintageNet.configure("mesh0", %{
  type: VintageNetWiFi,
  vintage_net_wifi: %{
    user_mpm: 1,
    networks: [
      %{
        ssid: "my-mesh",
        key_mgmt: :none,
        mode: :mesh
      }
    ]
  }
})

Mesh nodes connected to external networks can set so called "meshgate" params. See this document for more information

VintageNet.configure("mesh0", %{
  type: VintageNetWiFi,
  vintage_net_wifi: %{
    user_mpm: 1,
    networks: [
      %{
        ssid: mesh_id,
        key_mgmt: :none,
        mode: :mesh,
        mesh_hwmp_rootmode: 4,
        mesh_gate_announcements: 1
      }
    ]
  }
})

Note that the example mesh configuration does not contain IP address settings. All standard IP schemes are acceptable, but which one to use depends on the network configuration. The simplest way to test the mesh network is to have every node configure a static predictable IP address. DHCP will also work, but this forces a "client/server" configuration meaning that nodes joining the network will need to decide if they should be a DHCP server or client.

Properties

In addition to the common vintage_net properties for all interface types, this technology reports the following:

Property Values Description
access_points [%AccessPoint{}] A list of access points as found by the most recent scan
clients ["11:22:33:44:55:66"] A list of clients connected to the access point when using mode: :ap
current_ap %AccessPoint{} The currently associated access point
peers [%MeshPeer{}] a list of mesh peers that the current node knows about when using mode: :mesh

Access points are identified by their BSSID. Information about an access point has the following form:

%VintageNetWiFi.AccessPoint{
  band: :wifi_5_ghz,
  bssid: "8a:8a:20:88:7a:50",
  channel: 149,
  flags: [:wpa2_psk_ccmp, :ess],
  frequency: 5745,
  signal_dbm: -76,
  signal_percent: 57,
  ssid: "MyNetwork"
}

Mesh peers are identified by their BSSID. Information about a peer has the following form:

%VintageNetWiFi.MeshPeer{
  active_path_selection_metric_id: 1,
  active_path_selection_protocol_id: 1,
  age: 2339,
  authentication_protocol_id: 0,
  band: :wifi_2_4_ghz,
  beacon_int: 1000,
  bss_basic_rate_set: "10 20 55 110 60 120 240",
  bssid: "f8:a2:d6:b5:d4:07",
  capabilities: 0,
  channel: 5,
  congestion_control_mode_id: 0,
  est_throughput: 65000,
  flags: [:mesh],
  frequency: 2432,
  id: 7,
  mesh_capability: 9,
  mesh_formation_info: 2,
  mesh_id: "my-mesh",
  noise_dbm: -89,
  quality: 0,
  signal_dbm: -27,
  signal_percent: 97,
  snr: 62,
  ssid: "my-mesh",
  synchronization_method_id: 1
}

Applications can scan for access points in a couple ways. The first is to call VintageNet.scan("wlan0"), wait for a second, and then call VintageNet.get(["interface", "wlan0", "access_points"]). This works for scanning networks once or twice. A better way is to subscribe to the "access_points" property and then call VintageNet.scan("wlan0") on a timer. The "access_points" property updates as soon as the WiFi module notifies that it is complete so applications don't need to guess how long to wait.

Signal quality info in STA (client) mode

You can send ioctl command to get information about signal level, quality and other info when connected to network in STA mode. Run:

VintageNet.ioctl("wlan0", :signal_poll)

Example output:

{:ok, %VintageNetWiFi.SignalInfo{
  center_frequency1: 2462,
  center_frequency2: 0,
  frequency: 2472,
  linkspeed: 300,
  signal_dbm: -32,
  signal_percent: 94,
  width: "40 MHz"
}}

Debugging

Unfortunately, when you're getting started for the very first time, WiFi can be quite frustrating. Error messages and logs are not all that helpful. The first debugging step is to connect to your device (over a UART or USB Gadget or maybe a wired Ethernet connection). Run:

iex> VintageNet.info

Double check that all of your parameters are set correctly. The :psk cannot be checked here, so if you suspect that's wrong, double check your config.exs. The next step is to look at log messages for connection errors. On Nerves devices, run RingLogger.next at the IEx prompt.

About

WiFi networking for VintageNet

License:Apache License 2.0


Languages

Language:Elixir 96.0%Language:C 2.6%Language:Makefile 1.1%Language:Shell 0.2%Language:Ruby 0.0%