Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set region to unknown on startup #413

Merged
merged 5 commits into from
Apr 7, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
508 changes: 252 additions & 256 deletions Cargo.lock

Large diffs are not rendered by default.

14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,17 @@ helium-gateway pre-installed, manual installation requires you to:
Supported values are `stdio` or `syslog`. Note you may need to configure
the `syslog` service on your device to accept the logs.

6. Configure the region if required. The default region of the gateway is
`US915`, if your region is different you can set the right one in the
`settings.toml` file.
6. Configure the region if required. The default region of the gateway is set to
`UKNOWN`, and fetched from the asserted location of the gateway. Setting the
regioon to a known region or caching the last fetched region and using the
jeffgrunewald marked this conversation as resolved.
Show resolved Hide resolved
`GW_REGION` environment variable on startup will allow the gateway to use the
correct region for uplinks immediately, while the region parameters are
retrieved.

The supported region values are listed in the [region protobuf definition](https://github.com/helium/proto/blob/master/src/region.proto)

**NOTE**: This regional setting is only used for uplinks. Due to TX power
regulations, the gateway location needs to be asserted on the blockchain to
be able to send downlinks.
**NOTE**: Due to TX power regulations, the gateway location needs to be
asserted on the blockchain to be able to send downlinks.

7. Start the service by either starting it manually or hooking it into the
`init.d`, `systemd`, or equivalent system services for your platform. Consult
Expand Down
4 changes: 1 addition & 3 deletions beacon/src/beacon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,7 @@ impl Beacon {
) -> Result<Self> {
match remote_entropy.version {
0 | 1 => {
if region_params.params.is_empty() {
return Err(Error::no_region_params());
}
region_params.check_valid()?;

let seed_data = {
let mut hasher = Sha256::new();
Expand Down
24 changes: 23 additions & 1 deletion beacon/src/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,25 @@ impl From<&Region> for i32 {
}
}

impl Default for Region {
fn default() -> Self {
Region(ProtoRegion::Unknown)
}
}

impl Region {
pub fn from_i32(v: i32) -> Result<Self> {
ProtoRegion::from_i32(v)
.map(Self)
.ok_or_else(|| Error::unsupported_region(v))
}

pub fn is_unknown(&self) -> bool {
self.0 == ProtoRegion::Unknown
}
}

#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default)]
pub struct RegionParams {
pub gain: Decimal,
pub region: Region,
Expand Down Expand Up @@ -164,10 +174,22 @@ impl RegionParams {
params,
})
}

pub fn is_unknown(&self) -> bool {
self.region.is_unknown()
}
}

impl RegionParams {
pub fn check_valid(&self) -> Result {
if self.is_unknown() || self.params.is_empty() {
return Err(Error::no_region_params());
}
Ok(())
}

pub fn max_eirp(&self) -> Result<Decimal> {
self.check_valid()?;
self.params
.iter()
.max_by_key(|p| p.max_eirp)
Expand Down
6 changes: 4 additions & 2 deletions config/settings.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ api = 4467

# The default region to use until a region is received from the Helium network.
# This value should line up with the configured region of the semtech packet
# forwarder.
region = "US915"
# forwarder. Note: Not setting this here or with a GW_REGION env var will stop
# packet and poc beacong until the correct asserted region is retrieved.
madninja marked this conversation as resolved.
Show resolved Hide resolved
#
# region = "US915"

[log]
# The logging level to assume on startup
Expand Down
9 changes: 2 additions & 7 deletions src/beaconer.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
//! This module provides proof-of-coverage (PoC) beaconing support.

use crate::{
error::RegionError,
gateway::{self, BeaconResp},
impl_msg_sign, region_watcher,
service::{entropy::EntropyService, poc::PocIotService},
Expand Down Expand Up @@ -133,9 +132,7 @@ impl Beaconer {
}

pub async fn mk_beacon(&mut self) -> Result<beacon::Beacon> {
if self.region_params.params.is_empty() {
return Err(RegionError::no_region_params());
}
self.region_params.check_valid()?;

let mut entropy_service = EntropyService::new(self.entropy_uri.clone());
let remote_entropy = entropy_service.get_entropy().await?;
Expand Down Expand Up @@ -225,8 +222,6 @@ impl Beaconer {
}

async fn handle_received_beacon(&mut self, packet: PacketUp) {
info!("received possible PoC payload: {packet:?}");

if let Some(last_beacon) = &self.last_beacon {
if packet.payload() == last_beacon.data {
info!("ignoring last self beacon witness");
Expand Down Expand Up @@ -266,7 +261,7 @@ impl Beaconer {
}

async fn handle_secondary_beacon(&mut self, report: poc_lora::LoraWitnessReportReqV1) {
if self.region_params.params.is_empty() {
if self.region_params.check_valid().is_err() {
warn!("no region params for secondary beacon");
return;
};
Expand Down
6 changes: 5 additions & 1 deletion src/cmd/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,11 @@ impl InfoCache {
}
let mut client = LocalClient::new(self.port).await?;
let region = client.region().await?;
self.region = Some(region);
self.region = if region.is_unknown() {
None
} else {
Some(region)
};
Ok(region)
}

Expand Down
36 changes: 24 additions & 12 deletions src/gateway.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ use semtech_udp::{
tx_ack::Error as TxAckErr,
CodingRate, MacAddress, Modulation,
};
use std::{
convert::TryFrom,
time::{Duration, Instant},
};
use std::time::{Duration, Instant};
use tracing::{debug, info, warn};

pub const DOWNLINK_TIMEOUT: Duration = Duration::from_secs(5);
Expand Down Expand Up @@ -135,15 +132,17 @@ impl Gateway {
Event::ClientDisconnected((mac, addr)) => {
info!(%mac, %addr, "disconnected packet forwarder")
}
Event::PacketReceived(rxpk, _gateway_mac) => match PacketUp::try_from(rxpk) {
Ok(packet) if packet.is_potential_beacon() => {
self.beacons.received_beacon(packet).await
}
Ok(packet) => self.handle_uplink(packet, Instant::now()).await,
Err(err) => {
warn!(%err, "ignoring push_data");
Event::PacketReceived(rxpk, _gateway_mac) => {
match PacketUp::from_rxpk(rxpk, self.region_params.region) {
Ok(packet) if packet.is_potential_beacon() => {
self.handle_potential_beacon(packet).await;
}
Ok(packet) => self.handle_uplink(packet, Instant::now()).await,
Err(err) => {
warn!(%err, "ignoring push_data");
}
}
},
}
Event::NoClientWithMac(_packet, mac) => {
info!(%mac, "ignoring send to client with unknown MAC")
}
Expand All @@ -154,7 +153,20 @@ impl Gateway {
Ok(())
}

async fn handle_potential_beacon(&mut self, packet: PacketUp) {
if self.region_params.is_unknown() {
info!(downlink_mac = %self.downlink_mac, uplink = %packet, "ignored potential beacon, no region");
return;
}
info!(downlink_mac = %self.downlink_mac, uplink = %packet, "received potential beacon");
self.beacons.received_beacon(packet).await
}

async fn handle_uplink(&mut self, packet: PacketUp, received: Instant) {
if self.region_params.is_unknown() {
info!(downlink_mac = %self.downlink_mac, uplink = %packet, "ignored uplink, no region");
return;
}
info!(downlink_mac = %self.downlink_mac, uplink = %packet, "received uplink");
self.uplinks.uplink(packet, received).await;
}
Expand Down
52 changes: 24 additions & 28 deletions src/packet.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{error::DecodeError, Error, Result};
use crate::{error::DecodeError, Error, Region, Result};
use helium_proto::services::{
poc_lora,
router::{PacketRouterPacketDownV1, PacketRouterPacketUpV1},
Expand Down Expand Up @@ -57,33 +57,6 @@ impl fmt::Display for PacketUp {
}
}

impl TryFrom<push_data::RxPk> for PacketUp {
type Error = Error;

fn try_from(rxpk: push_data::RxPk) -> Result<Self> {
if rxpk.get_crc_status() != &CRC::OK {
return Err(DecodeError::invalid_crc());
}
let rssi = rxpk
.get_signal_rssi()
.unwrap_or_else(|| rxpk.get_channel_rssi());

let packet = PacketRouterPacketUpV1 {
rssi,
timestamp: *rxpk.get_timestamp() as u64,
payload: rxpk.get_data().to_vec(),
frequency: to_hz(*rxpk.get_frequency()) as u32,
datarate: datarate::to_proto(rxpk.get_datarate())? as i32,
snr: rxpk.get_snr(),
region: 0,
hold_time: 0,
gateway: vec![],
signature: vec![],
};
Ok(Self(packet))
}
}

impl TryFrom<PacketUp> for poc_lora::LoraWitnessReportReqV1 {
type Error = Error;
fn try_from(value: PacketUp) -> Result<Self> {
Expand All @@ -110,6 +83,29 @@ impl TryFrom<PacketUp> for poc_lora::LoraWitnessReportReqV1 {
}

impl PacketUp {
pub fn from_rxpk(rxpk: push_data::RxPk, region: Region) -> Result<Self> {
if rxpk.get_crc_status() != &CRC::OK {
return Err(DecodeError::invalid_crc());
}
let rssi = rxpk
.get_signal_rssi()
.unwrap_or_else(|| rxpk.get_channel_rssi());

let packet = PacketRouterPacketUpV1 {
rssi,
timestamp: *rxpk.get_timestamp() as u64,
payload: rxpk.get_data().to_vec(),
frequency: to_hz(*rxpk.get_frequency()) as u32,
datarate: datarate::to_proto(rxpk.get_datarate())? as i32,
snr: rxpk.get_snr(),
region: region.into(),
hold_time: 0,
gateway: vec![],
signature: vec![],
};
Ok(Self(packet))
}

pub fn is_potential_beacon(&self) -> bool {
Self::parse_header(self.payload())
.map(|header| header.mtype() == lorawan::MType::Proprietary)
Expand Down
14 changes: 1 addition & 13 deletions src/packet_router/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use crate::{
gateway,
message_cache::{CacheMessage, MessageCache},
region_watcher,
service::packet_router::PacketRouterService,
sync, Base64, Keypair, MsgSign, PacketUp, RegionParams, Result, Settings,
sync, Base64, Keypair, MsgSign, PacketUp, Result, Settings,
};
use exponential_backoff::Backoff;
use helium_proto::services::router::{PacketRouterPacketDownV1, PacketRouterPacketUpV1};
Expand Down Expand Up @@ -53,11 +52,9 @@ impl MessageSender {

pub struct PacketRouter {
messages: MessageReceiver,
region_watch: region_watcher::MessageReceiver,
transmit: gateway::MessageSender,
service: PacketRouterService,
reconnect_retry: u32,
region_params: RegionParams,
keypair: Arc<Keypair>,
store: MessageCache<PacketUp>,
}
Expand All @@ -66,18 +63,14 @@ impl PacketRouter {
pub fn new(
settings: &Settings,
messages: MessageReceiver,
region_watch: region_watcher::MessageReceiver,
transmit: gateway::MessageSender,
) -> Self {
let router_settings = &settings.router;
let service =
PacketRouterService::new(router_settings.uri.clone(), settings.keypair.clone());
let store = MessageCache::new(router_settings.queue);
let region_params = region_watcher::current_value(&region_watch);
Self {
service,
region_params,
region_watch,
keypair: settings.keypair.clone(),
transmit,
messages,
Expand Down Expand Up @@ -118,10 +111,6 @@ impl PacketRouter {
}
None => warn!("ignoring closed message channel"),
},
region_change = self.region_watch.changed() => match region_change {
Ok(()) => self.region_params = region_watcher::current_value(&self.region_watch),
Err(_) => warn!("region watch disconnected")
},
_ = time::sleep_until(reconnect_sleep) => {
reconnect_sleep = self.handle_reconnect(&reconnect_backoff).await;
},
Expand Down Expand Up @@ -182,7 +171,6 @@ impl PacketRouter {
packet: CacheMessage<PacketUp>,
) -> Result<PacketRouterPacketUpV1> {
let mut uplink: PacketRouterPacketUpV1 = packet.into_inner().into();
uplink.region = self.region_params.region.into();
uplink.gateway = self.keypair.public_key().into();
uplink.signature = uplink.sign(self.keypair.clone()).await?;
Ok(uplink)
Expand Down
12 changes: 7 additions & 5 deletions src/region_watcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl RegionWatcher {

pub async fn run(&mut self, shutdown: &triggered::Listener) -> Result {
info!(
default_region = %self.default_region,
%self.default_region,
"starting",
);

Expand Down Expand Up @@ -102,20 +102,22 @@ impl RegionWatcher {
warn!(
pubkey = %service_uri.pubkey,
uri = %service_uri.uri,
region = %current_region,
default_region = %current_region,
%err,
"failed to get region_params"
);
Err(err)
}
other => {
Ok(other) => {
let region = other.as_ref().map(|params| params.region).unwrap_or_default();
info!(
pubkey = %service_uri.pubkey,
uri = %service_uri.uri,
region = %current_region,
default_region = %current_region,
%region,
"fetched config region_params",
);
other
Ok(other)
}
}
}
Expand Down
7 changes: 1 addition & 6 deletions src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,7 @@ pub async fn run(shutdown: &triggered::Listener, settings: &Settings) -> Result
let mut beaconer =
beaconer::Beaconer::new(settings, beacon_rx, region_rx.clone(), gateway_tx.clone());

let mut router = packet_router::PacketRouter::new(
settings,
router_rx,
region_rx.clone(),
gateway_tx.clone(),
);
let mut router = packet_router::PacketRouter::new(settings, router_rx, gateway_tx.clone());

let mut gateway = gateway::Gateway::new(
settings,
Expand Down
5 changes: 4 additions & 1 deletion src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ pub struct Settings {
/// location.
pub onboarding: Option<String>,
/// The lorawan region to use. This value should line up with the configured
/// region of the semtech packet forwarder. Defaults to "US915"
/// region of the semtech packet forwarder. Defaults to the "UNKNOWN" region
/// which will delay poc and packet activity for a short duration until the
/// asserted location/region is fetched.
#[serde(default)]
pub region: Region,
/// Log settings
pub log: LogSettings,
Expand Down