diff --git a/doc/wifi.md b/doc/wifi.md index e01d8521..3aa7d3f3 100644 --- a/doc/wifi.md +++ b/doc/wifi.md @@ -10,14 +10,35 @@ host virtual interfaces. Infix uses a two-layer WiFi architecture: 1. **WiFi Radio (PHY layer)**: Represents the physical wireless hardware - - Configured via `ietf-hardware` module - - Controls channel, transmit power, regulatory domain - - One radio can host multiple virtual interfaces + - Configured via `ietf-hardware` module + - Controls channel, transmit power, regulatory domain + - One radio can host multiple virtual interfaces 2. **WiFi Interface (Network layer)**: Virtual interface on a radio - - Configured via `infix-interfaces` module - - Can operate in Station (client) or Access Point mode - - Each interface references a parent radio + - Configured via `infix-interfaces` module + - Can operate in Station (client) or Access Point mode + - Each interface references a parent radio + +## Naming Conventions + +Like other interface types in Infix, WiFi components follow naming conventions +that allow the CLI to automatically infer types: + +| **Name Pattern** | **Type** | **Description** | +|------------------|-----------------|------------------------------------------| +| `radioN` | WiFi Radio | Hardware component for WiFi PHY | +| `wifiN` | WiFi Interface | Virtual WiFi interface on a radio | + +Where `N` is a number (0, 1, 2, ...). + +> [!TIP] +> Using these naming conventions simplifies configuration since type/class +> settings are automatically inferred. For example, creating a hardware +> component named `radio0` automatically sets its class to `wifi`, enabling +> the `wifi-radio` configuration container. +> +> **Note:** This inference only works with the CLI. Configuring WiFi over +> NETCONF or RESTCONF requires setting the class/type explicitly. ## Current Limitations @@ -31,15 +52,38 @@ Wi-Fi support is primarily tested with Realtek chipset-based adapters. ### Known Working Chipsets -- Built-in Wi-Fi on Banana Pi r3 +- Built-in Wi-Fi on Banana Pi BPi-R3 - Built-in Wi-Fi on Raspberry Pi 4/CM4 -- RTL8821CU -- Other Realtek chipsets may work but are not guaranteed +- Realtek: + - RTL8188CU + - RTL8188FU + - RTL8821CU +Other Realtek chipsets may work but are not tested. -> [!NOTE] Some Realtek chipsets require proprietary drivers not included in the standard kernel -> Firmware requirements vary by chipset -> Check kernel logs if your adapter is not detected +> [!NOTE] +> Some Realtek chipsets require proprietary drivers not included in the +> standard kernel. +> +> - Firmware requirements vary by chipset +> - Check kernel logs if your adapter is not detected + +### USB WiFi Dongles + +USB WiFi dongles may be slow to initialize at boot due to firmware +loading. If your USB dongle is not detected reliably, configure a +`probe-timeout` on the radio to wait for the PHY: + +
admin@example:/> configure
+admin@example:/config/> edit hardware component radio0 wifi-radio
+admin@example:/config/hardware/component/radio0/wifi-radio/> set probe-timeout 30
+admin@example:/config/hardware/component/radio0/wifi-radio/> leave
+
+ +This waits up to 30 seconds for the radio PHY to appear before creating +WiFi interfaces. If the PHY is not detected within the timeout, a dummy +interface is created as a placeholder, allowing IP configuration to proceed. +Reboot when the radio becomes available. ## Radio Configuration @@ -48,47 +92,73 @@ Radios are automatically discovered and named `radio0`, `radio1`, etc. ### Country Code and Regulatory Compliance -> [!IMPORTANT] -> The `country-code` setting is **legally required** and determines which WiFi channels and power levels are permitted in your location. Using an incorrect country code may violate local wireless regulations. +The radio defaults to "00" for World domain, but some systems may ship with a +factory default country code (typically "DE" for the BPi-R3). -**Factory default**: Systems may ship with a default country code (typically "DE" for Germany in European builds or "00" for World domain). **You must configure the correct country code for your deployment location.** +> [!IMPORTANT] Legal notice! +> The `country-code` setting is **legally required** and determines +> which WiFi channels and power levels are permitted in your +> location. Using an incorrect country code may violate local wireless +> regulations. -**Common country codes**: -- Europe: DE (Germany), SE (Sweden), GB (UK), FR (France), ES (Spain) -- Americas: US (United States), CA (Canada), BR (Brazil) -- Asia-Pacific: JP (Japan), AU (Australia), CN (China) +**Common country codes, see [ISO 3166-1 alpha-2][1] for the complete list**: -See [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) for the complete list. +- Europe: + - DE: Germany + - SE: Sweden + - GB: UK + - FR: France + - ES: Spain +- Americas: + - US: United States + - CA: Canada + - BR: Brazil +- Asia-Pacific: + - JP: Japan + - AU: Australia + - CN: China ### Basic Radio Setup Configure the radio with channel, power, and regulatory domain. **For Station (client) mode:** -``` -admin@example:/> configure -admin@example:/config/> edit hardware component radio0 wifi-radio -admin@example:/config/hardware/component/radio0/wifi-radio/> set country-code DE -admin@example:/config/hardware/component/radio0/wifi-radio/> leave -``` + +
admin@example:/> configure
+admin@example:/config/> edit hardware component radio0 wifi-radio
+admin@example:/config/hardware/component/radio0/wifi-radio/> set country-code DE
+admin@example:/config/hardware/component/radio0/wifi-radio/> leave
+
**For Access Point mode:** -``` -admin@example:/> configure -admin@example:/config/> edit hardware component radio0 wifi-radio -admin@example:/config/hardware/component/radio0/wifi-radio/> set country-code DE -admin@example:/config/hardware/component/radio0/wifi-radio/> set band 5GHz -admin@example:/config/hardware/component/radio0/wifi-radio/> set channel 36 -admin@example:/config/hardware/component/radio0/wifi-radio/> leave -``` + +
admin@example:/> configure
+admin@example:/config/> edit hardware component radio0 wifi-radio
+admin@example:/config/hardware/component/radio0/wifi-radio/> set country-code DE
+admin@example:/config/hardware/component/radio0/wifi-radio/> set band 5GHz
+admin@example:/config/hardware/component/radio0/wifi-radio/> set channel 36
+admin@example:/config/hardware/component/radio0/wifi-radio/> leave
+
**Key radio parameters:** -- `country-code`: Two-letter ISO 3166-1 code - determines allowed channels and maximum power. Examples: US, DE, GB, SE, FR, JP. **Must match your physical location for legal compliance.** -- `band`: 2.4GHz, 5GHz, or 6GHz (required for AP mode). Automatically enables appropriate WiFi standards (2.4GHz: 802.11n/ax, 5GHz: 802.11n/ac/ax, 6GHz: 802.11ax) -- `channel`: Channel number (1-196) or "auto" (required for AP mode). When set to "auto", defaults to channel 6 for 2.4GHz, channel 36 for 5GHz, or channel 109 for 6GHz + +- `country-code`: Two-letter [ISO 3166-1 alpha-2][1] code, determines allowed + channels and maximum power. Examples: US, DE, GB, SE, FR, JP. + **⚠ Must match your physical location for legal compliance! ⚠** +- `band`: 2.4GHz, 5GHz, or 6GHz (required for AP mode). Automatically enables + appropriate WiFi standards: + - 2.4GHz: 802.11n/ax + - 5GHz: 802.11n/ac/ax + - 6GHz: 802.11ax +- `channel`: Channel number (1-196) or "auto". When set to "auto", defaults to + channel 6 for 2.4GHz, channel 36 for 5GHz, or channel 109 for 6GHz +- `probe-timeout`: Seconds to wait for PHY detection at boot (default: 0). Set + to a non-zero value (e.g., 30) for USB WiFi dongles that are slow to + initialize due to firmware loading > [!NOTE] -> TX power and channel width are automatically determined by the driver based on regulatory constraints, PHY mode, and hardware capabilities. +> TX power and channel width are automatically determined by the driver +> based on regulatory constraints, PHY mode, and hardware capabilities. ### WiFi 6 (802.11ax) Support @@ -96,16 +166,18 @@ WiFi 6 (802.11ax) is always enabled in AP mode on all bands, providing improved performance through features like OFDMA, BSS Coloring, and beamforming. **WiFi 6 Features (always enabled):** + - **OFDMA**: Better multi-user efficiency in dense environments - **BSS Coloring**: Reduced interference from neighboring networks - **Beamforming**: Improved signal quality and range **Requirements:** + - Hardware must support 802.11ax - Client devices must support WiFi 6 for full benefits - Older WiFi 5/4 clients can still connect but won't use WiFi 6 features -## Discovering Available Networks (Scanning) +## Discovering Available Networks Before connecting to a WiFi network, you need to discover which networks are available. Infix automatically scans for networks when a WiFi interface @@ -118,21 +190,19 @@ interface referencing it: **Step 1: Configure the radio** -``` -admin@example:/> configure -admin@example:/config/> edit hardware component radio0 wifi-radio -admin@example:/config/hardware/component/radio0/wifi-radio/> set country-code DE -admin@example:/config/hardware/component/radio0/wifi-radio/> leave -``` +
admin@example:/> configure
+admin@example:/config/> edit hardware component radio0 wifi-radio
+admin@example:/config/hardware/component/radio0/wifi-radio/> set country-code DE
+admin@example:/config/hardware/component/radio0/wifi-radio/> leave
+
**Step 2: Create WiFi interface with radio reference only** -``` -admin@example:/> configure -admin@example:/config/> edit interface wifi0 -admin@example:/config/interface/wifi0/> set wifi radio radio0 -admin@example:/config/interface/wifi0/> leave -``` +
admin@example:/> configure
+admin@example:/config/> edit interface wifi0
+admin@example:/config/interface/wifi0/> set wifi radio radio0
+admin@example:/config/interface/wifi0/> leave
+
The system will now start scanning in the background. The interface will operate in scan-only mode until you configure a specific mode (station or @@ -142,25 +212,30 @@ access-point). Use `show interface` to see discovered networks and their signal strength: -``` -admin@example:/> show interface wifi0 +
admin@example:/> show interface wifi0
 name                : wifi0
 type                : wifi
 index               : 3
 mtu                 : 1500
-operational status  : down
+operational status  : up
+ip forwarding       : enabled
 physical address    : f0:09:0d:36:5f:86
-ipv4 addresses      :
+ipv4 addresses      : 192.168.1.100/24 (dhcp)
 ipv6 addresses      :
-SSID                : ----
-Signal              : ----
-
-SSID                                    SECURITY                      SIGNAL
-MyNetwork                               WPA2-Personal                 excellent
-GuestWiFi                               WPA2-WPA3-Personal            good
-CoffeeShop                              Open                          fair
-IoT-Devices                             WPA2-Personal                 good
-```
+in-octets           : 148388
+out-octets          : 24555
+mode                : station
+ssid                : MyNetwork
+signal              : -45 dBm (good)
+rx bitrate          : 72.2 Mbps
+tx bitrate          : 86.6 Mbps
+──────────────────────────────────────────────────────────────────────
+Available Networks
+SSID                 BSSID              SECURITY       SIGNAL  CHANNEL
+MyNetwork            b4:fb:e4:17:b6:a7  WPA2-Personal  good          6
+GuestWiFi            c8:3a:35:12:34:56  WPA2-Personal  fair         11
+CoffeeShop           00:1a:2b:3c:4d:5e  Open           bad           1
+
In the CLI, signal strength is reported as: excellent, good, fair or bad. For precise RSSI values in dBm, use NETCONF or RESTCONF to access the @@ -176,43 +251,44 @@ scan for available networks and identify the SSID you want to connect to. Create a keystore entry for your WiFi password (8-63 characters): -``` -admin@example:/> configure -admin@example:/config/> edit keystore symmetric-key my-wifi-key -admin@example:/config/keystore/…/my-wifi-key/> set key-format wifi-preshared-key-format -admin@example:/config/keystore/…/my-wifi-key/> set symmetric-key MyPassword123 -admin@example:/config/keystore/…/my-wifi-key/> leave -``` +
admin@example:/> configure
+admin@example:/config/> edit keystore symmetric-key my-wifi-key
+admin@example:/config/keystore/…/my-wifi-key/> set key-format wifi-preshared-key-format
+admin@example:/config/keystore/…/my-wifi-key/> set symmetric-key MyPassword123
+admin@example:/config/keystore/…/my-wifi-key/> leave
+
### Step 2: Connect to Network Configure station mode with the SSID and password to connect: -``` -admin@example:/> configure -admin@example:/config/> edit interface wifi0 -admin@example:/config/interface/wifi0/> set wifi station ssid MyHomeNetwork -admin@example:/config/interface/wifi0/> set wifi station security secret my-wifi-key -admin@example:/config/interface/wifi0/> leave -``` +
admin@example:/> configure
+admin@example:/config/> edit interface wifi0
+admin@example:/config/interface/wifi0/> set wifi station ssid MyHomeNetwork
+admin@example:/config/interface/wifi0/> set wifi station security secret my-wifi-key
+admin@example:/config/interface/wifi0/> leave
+
The connection attempt will start immediately. You can verify the connection status: -``` -admin@example:/> show interface wifi0 +
admin@example:/> show interface wifi0
 name                : wifi0
 type                : wifi
 operational status  : up
 physical address    : f0:09:0d:36:5f:86
 SSID                : MyHomeNetwork
 Signal              : excellent
-```
+
**Station configuration parameters:** + - `radio`: Reference to the WiFi radio (mandatory) - already set during scanning - `station ssid`: Network name to connect to (mandatory) -- `station security mode`: `auto` (default, WPA2/WPA3 auto-negotiation) or `disabled` (open network) -- `station security secret`: Reference to keystore entry (required unless mode is `disabled`) +- `station security mode`: + - `auto`: default, WPA2/WPA3 auto-negotiation + - `disabled`: open network +- `station security secret`: Reference to keystore entry, required unless mode + is `disabled` > [!NOTE] > The `auto` security mode automatically selects WPA3-SAE or WPA2-PSK based on @@ -228,23 +304,33 @@ a WiFi radio. ### Basic AP Configuration First, ensure the radio is configured (see Radio Configuration above). Then -create an AP interface: +create a keystore entry for your WiFi password and configure the AP interface: -``` -admin@example:/> configure -admin@example:/config/> edit interface wifi0 -admin@example:/config/interface/wifi0/> set wifi radio radio0 -admin@example:/config/interface/wifi0/> set wifi access-point ssid MyNetwork -admin@example:/config/interface/wifi0/> set wifi access-point security mode wpa2-personal -admin@example:/config/interface/wifi0/> set wifi access-point security secret example -admin@example:/config/interface/wifi0/> leave -``` +**Step 1: Create keystore entry for the WiFi password** + +
admin@example:/> configure
+admin@example:/config/> edit keystore symmetric-key my-wifi-secret
+admin@example:/config/keystore/…/my-wifi-secret/> set key-format wifi-preshared-key-format
+admin@example:/config/keystore/…/my-wifi-secret/> set symmetric-key MySecurePassword123
+admin@example:/config/keystore/…/my-wifi-secret/> end
+
+ +**Step 2: Create the AP interface** + +
admin@example:/config/> edit interface wifi0
+admin@example:/config/interface/wifi0/> set wifi radio radio0
+admin@example:/config/interface/wifi0/> set wifi access-point ssid MyNetwork
+admin@example:/config/interface/wifi0/> set wifi access-point security mode wpa2-personal
+admin@example:/config/interface/wifi0/> set wifi access-point security secret my-wifi-secret
+admin@example:/config/interface/wifi0/> leave
+
> [!NOTE] > Using `wifiN` as the interface name automatically sets the type to WiFi. > Alternatively, you can use any name and explicitly set `type wifi`. **Access Point configuration parameters:** + - `radio`: Reference to the WiFi radio (mandatory) - `access-point ssid`: Network name (SSID) to broadcast - `access-point hidden`: Set to `true` to hide SSID (optional, default: false) @@ -252,6 +338,7 @@ admin@example:/config/interface/wifi0/> leave - `access-point security secret`: Reference to keystore entry (for secured networks) **Security modes:** + - `open`: No encryption (not recommended) - `wpa2-personal`: WPA2-PSK (most compatible) - `wpa3-personal`: WPA3-SAE (more secure, requires WPA3-capable clients) @@ -261,9 +348,8 @@ admin@example:/config/interface/wifi0/> leave To create a hidden network that doesn't broadcast its SSID: -``` -admin@example:/config/interface/wifi0/> set wifi access-point hidden true -``` +
admin@example:/config/interface/wifi0/> set wifi access-point hidden true
+
### Multi-SSID Configuration @@ -273,59 +359,56 @@ IoT devices, or segregating traffic into different VLANs. **Step 1: Configure the radio** (shared by all APs) -``` -admin@example:/> configure -admin@example:/config/> edit hardware component radio0 wifi-radio -admin@example:/config/hardware/component/radio0/wifi-radio/> set country-code DE -admin@example:/config/hardware/component/radio0/wifi-radio/> set band 5GHz -admin@example:/config/hardware/component/radio0/wifi-radio/> set channel 36 -admin@example:/config/hardware/component/radio0/wifi-radio/> leave -``` +
admin@example:/> configure
+admin@example:/config/> edit hardware component radio0 wifi-radio
+admin@example:/config/hardware/component/radio0/wifi-radio/> set country-code DE
+admin@example:/config/hardware/component/radio0/wifi-radio/> set band 5GHz
+admin@example:/config/hardware/component/radio0/wifi-radio/> set channel 36
+admin@example:/config/hardware/component/radio0/wifi-radio/> leave
+
**Step 2: Configure keystore secrets** -``` -admin@example:/> configure -admin@example:/config/> edit keystore symmetric-key main-secret -admin@example:/config/keystore/…/main-secret/> set key-format wifi-preshared-key-format -admin@example:/config/keystore/…/main-secret/> set symmetric-key MyMainPassword -admin@example:/config/> edit keystore symmetric-key guest-secret -admin@example:/config/keystore/…/guest-secret/> set key-format wifi-preshared-key-format -admin@example:/config/keystore/…/guest-secret/> set symmetric-key GuestPassword123 -admin@example:/config/> edit keystore symmetric-key iot-secret -admin@example:/config/keystore/…/iot-secret/> set key-format wifi-preshared-key-format -admin@example:/config/keystore/…/iot-secret/> set symmetric-key IoTDevices2025 -admin@example:/config/keystore/…/iot-secret/> leave -``` +
admin@example:/> configure
+admin@example:/config/> edit keystore symmetric-key main-secret
+admin@example:/config/keystore/…/main-secret/> set key-format wifi-preshared-key-format
+admin@example:/config/keystore/…/main-secret/> set symmetric-key MyMainPassword
+admin@example:/config/> edit keystore symmetric-key guest-secret
+admin@example:/config/keystore/…/guest-secret/> set key-format wifi-preshared-key-format
+admin@example:/config/keystore/…/guest-secret/> set symmetric-key GuestPassword123
+admin@example:/config/> edit keystore symmetric-key iot-secret
+admin@example:/config/keystore/…/iot-secret/> set key-format wifi-preshared-key-format
+admin@example:/config/keystore/…/iot-secret/> set symmetric-key IoTDevices2025
+admin@example:/config/keystore/…/iot-secret/> leave
+
**Step 3: Create multiple AP interfaces** (all on radio0) -``` -admin@example:/> configure +
admin@example:/> configure
 # Primary AP - Main network (WPA3 for maximum security)
-admin@example:/config/> edit interface wifi0
-admin@example:/config/interface/wifi0/> set wifi radio radio0
-admin@example:/config/interface/wifi0/> set wifi access-point ssid MainNetwork
-admin@example:/config/interface/wifi0/> set wifi access-point security mode wpa3-personal
-admin@example:/config/interface/wifi0/> set wifi access-point security secret main-secret
+admin@example:/config/> edit interface wifi0
+admin@example:/config/interface/wifi0/> set wifi radio radio0
+admin@example:/config/interface/wifi0/> set wifi access-point ssid MainNetwork
+admin@example:/config/interface/wifi0/> set wifi access-point security mode wpa3-personal
+admin@example:/config/interface/wifi0/> set wifi access-point security secret main-secret
 
 # Guest AP - Guest network (WPA2/WPA3 mixed for compatibility)
-admin@example:/config/> edit interface wifi1
-admin@example:/config/interface/wifi1/> set wifi radio radio0
-admin@example:/config/interface/wifi1/> set wifi access-point ssid GuestNetwork
-admin@example:/config/interface/wifi1/> set wifi access-point security mode wpa2-wpa3-personal
-admin@example:/config/interface/wifi1/> set wifi access-point security secret guest-secret
-admin@example:/config/interface/wifi1/> set custom-phys-address static 00:0c:43:26:60:01
+admin@example:/config/> edit interface wifi1
+admin@example:/config/interface/wifi1/> set wifi radio radio0
+admin@example:/config/interface/wifi1/> set wifi access-point ssid GuestNetwork
+admin@example:/config/interface/wifi1/> set wifi access-point security mode wpa2-wpa3-personal
+admin@example:/config/interface/wifi1/> set wifi access-point security secret guest-secret
+admin@example:/config/interface/wifi1/> set custom-phys-address static 00:0c:43:26:60:01
 
 # IoT AP - IoT devices (WPA2 for older device compatibility)
-admin@example:/config/> edit interface wifi2
-admin@example:/config/interface/wifi2/> set wifi radio radio0
-admin@example:/config/interface/wifi2/> set wifi access-point ssid IoT-Devices
-admin@example:/config/interface/wifi2/> set wifi access-point security mode wpa2-personal
-admin@example:/config/interface/wifi2/> set wifi access-point security secret iot-secret
-admin@example:/config/interface/wifi2/> set custom-phys-address static 00:0c:43:26:60:02
-admin@example:/config/interface/wifi2/> leave
-```
+admin@example:/config/> edit interface wifi2
+admin@example:/config/interface/wifi2/> set wifi radio radio0
+admin@example:/config/interface/wifi2/> set wifi access-point ssid IoT-Devices
+admin@example:/config/interface/wifi2/> set wifi access-point security mode wpa2-personal
+admin@example:/config/interface/wifi2/> set wifi access-point security secret iot-secret
+admin@example:/config/interface/wifi2/> set custom-phys-address static 00:0c:43:26:60:02
+admin@example:/config/interface/wifi2/> leave
+
> [!IMPORTANT] > **MAC Address Requirement for Multi-SSID:** @@ -342,12 +425,14 @@ admin@example:/config/interface/wifi2/> leave > - Tertiary (wifi2): `00:0c:43:26:60:02` (increment last octet) **Result:** Three SSIDs broadcasting simultaneously on radio0: + - `MainNetwork` (WPA3, most secure) - `GuestNetwork` (WPA2/WPA3 mixed mode) - `IoT-Devices` (WPA2 for compatibility) All APs on the same radio share the same channel and physical layer settings (configured at the radio level). Each AP can have its own: + - SSID (network name) - Security mode and passphrase - Hidden/visible SSID setting @@ -365,25 +450,32 @@ radio settings, and `show interface` to see all active AP interfaces. WiFi AP interfaces can be added to bridges to integrate wireless devices into your LAN: -``` -admin@example:/> configure -admin@example:/config/> edit interface br0 -admin@example:/config/interface/br0/> set type bridge +
admin@example:/> configure
+admin@example:/config/> edit interface br0
+admin@example:/config/interface/br0/> set type bridge
 
-admin@example:/config/> edit interface wifi0
-admin@example:/config/interface/wifi0/> set bridge-port bridge br0
-admin@example:/config/interface/wifi0/> leave
-```
+admin@example:/config/> edit interface wifi0
+admin@example:/config/interface/wifi0/> set bridge-port bridge br0
+admin@example:/config/interface/wifi0/> leave
+
-## Troubleshooting Connection Issues +## Troubleshooting Use `show interface wifi0` to verify signal strength and connection status. If issues arise, try the following troubleshooting steps: -1. **Verify signal strength**: Check that the target network shows "good" or "excellent" signal in scan results -2. **Check credentials**: Verify the preshared key in the keystore matches the network password -3. **Review logs**: Check system logs with `show log` for Wi-Fi related errors -4. **Regulatory compliance**: Ensure the country-code on the radio matches your location -5. **Hardware detection**: Confirm the WiFi radio appears in `show hardware` +1. **Verify signal strength**: Check that the target network shows + "good" or "excellent" signal in scan results +2. **Check credentials**: Verify the preshared key in the keystore + matches the network password +3. **Review logs**: Check system logs with `show log` for Wi-Fi related + errors +4. **Regulatory compliance**: Ensure the country-code on the radio + matches your location +5. **Hardware detection**: Confirm the WiFi radio appears in `show + hardware` -If issues persist, check the system log for specific error messages that can help identify the root cause. +If issues persist, check the system log for specific error messages that +can help identify the root cause. + +[1]: https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2