mirror of https://github.com/jgoerzen/xbnet.git
checkpointing
This commit is contained in:
parent
f9be18ccf3
commit
10dd26b7be
|
@ -1,11 +1,13 @@
|
|||
# XBee Networking Tools
|
||||
|
||||
This package is for doing fantastic things with your XBee device. You can, of course, already use it as a serial replacement, so you can run PPP and UUCP across it.
|
||||
This package is for doing fantastic things with your XBee device. You can, of course, already use it as a serial replacement, so you can run PPP and UUCP across it. XBee radios are low-cost, long-range, low-speed devices; with bitrates from 10Kbps to 250Kbps, they can reach many miles using simple antennas and low cost.
|
||||
|
||||
With xbnet, you can also run Ethernet across it. Or TCP/IP (IPv4 and IPv6). SPX if you want? I guess so.
|
||||
With xbnet, you can also run Ethernet across it. Or ZModem. Or TCP/IP (IPv4 and IPv6). SPX if you want? I guess so. SSH? Of course!
|
||||
|
||||
This is tested with the XBee SX modules, but ought to work with any modern XBee module.
|
||||
|
||||
XBee devices are particularly interesting because of their self-healing mesh (DigiMesh) technology. They will auto-route traffic to the destination, via intermediate hops if necessary. They also support bitrates high enough for a TCP stack, with nearly the range of LoRA.
|
||||
|
||||
This is a followup to, and fork of, my [lorapipe](https://github.com/jgoerzen/lorapipe) project, which is something similar for LoRA radios.
|
||||
|
||||
# Copyright
|
||||
|
|
386
doc/xbnet.1.md
386
doc/xbnet.1.md
|
@ -1,227 +1,85 @@
|
|||
% LORAPIPE(1) John Goerzen | lorapipe Manual
|
||||
% XBNET(1) John Goerzen | xbnet Manual
|
||||
% John Goerzen
|
||||
% October 2019
|
||||
|
||||
# NAME
|
||||
|
||||
lorapipe - Transfer data and run a network over LoRa long-range radios
|
||||
xbnet - Transfer data and run a network over XBee long-range radios
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
**lorapipe** [ *OPTIONS* ] **PORT** **COMMAND** [ *command_options* ]
|
||||
**xbnet** [ *OPTIONS* ] **PORT** **COMMAND** [ *command_options* ]
|
||||
|
||||
# OVERVIEW
|
||||
|
||||
**lorapipe** is designed to integrate LoRa long-range radios into a
|
||||
Unix/Linux system. In particular, lorapipe can:
|
||||
**xbnet** is designed to integrate XBee long-range radios into a
|
||||
Unix/Linux system. In particular, xbnet can:
|
||||
|
||||
- Bidirectionally pipe data across a LoRa radio system
|
||||
- Do an RF ping and report signal strength at each end
|
||||
- Operate an AX.25 network using LoRa, and atop it, TCP/IP
|
||||
- Bidirectionally pipe data across a XBee radio system
|
||||
- Do an RF ping
|
||||
- Operate as a virtual Ethernet device or a virtual tunnel device
|
||||
- Run TCP/IP (IPv4 and IPv6) atop either of these.
|
||||
|
||||
# HARDWARE REQUIREMENTS
|
||||
|
||||
**lorapipe** is designed to run with a Microchip RN2903/RN2483 as
|
||||
implemented by LoStik.
|
||||
**xbnet** is designed to run with a Digi XBee device. It is tested with the SX devices but should work with any.
|
||||
|
||||
Drivers for other hardware may be added in the future.
|
||||
|
||||
The Microchip firmware must be upgraded to 1.0.5 before running with
|
||||
**lorapipe**. Previous versions lacked the `radio rxstop` command,
|
||||
which is a severe limitation when receiving multiple packets rapidly.
|
||||
|
||||
See the documents tab for the
|
||||
[RN2093](https://www.microchip.com/wwwproducts/en/RN2903) and the
|
||||
[firmware upgrade
|
||||
guide](https://www.pocketmagic.net/rn2483-rn2903-firmware-upgrade-guide/) -
|
||||
note that the upgrade part is really finicky and you need the "offset" file.
|
||||
|
||||
# PROTOCOL
|
||||
|
||||
The **lorapipe pipe** command is the primary one of interest here. It
|
||||
will receive data on stdin, break it up into LoRa-sized packets (see
|
||||
**--maxpacketsize**), and transmit it across the radio. It also will
|
||||
receive data from the radio channel and send it to stdout. No attempt
|
||||
at encryption or authentication is made; all packets successfully
|
||||
decoded will be sent to stdout. Authentication and filtering is left
|
||||
to other layers of the stack atop **lorapipe**.
|
||||
XBee frames are smaller than typical Ethernet or TCP frames. XBee frames, in fact, are typically limited to about 255 bytes on the SX series; other devices may have different limits. Therefore, xbnet supports fragmentation and reassembly. It will split a frame to be transmitted into the size supported by XBee, and reassemble on the other end.
|
||||
|
||||
A thin layer atop **lorapipe pipe** is **lorapipe kiss**, which
|
||||
implements the AX.25 KISS protocol. It transmits each KISS frame it
|
||||
receives as a LoRa frame, and vice-versa. It performs rudimentary
|
||||
checking to ensure it is receiving valid KISS data, and will not pass
|
||||
anything else to stdout. This support can be used to build a TCP/IP
|
||||
network atop LoRa as will be shown below. Encryption and
|
||||
authentication could be added atop this by using tools such as OpenVPN
|
||||
or SSH.
|
||||
XBee, of course, cannot guarantee that all frames will be received, and therefore xbnet can't make that guarantee either. However, the protocols you may run atop it -- from UUCP to ZModem to TCP/IP -- should handle this.
|
||||
|
||||
**lorapipe** provides only the guarantees that LoRa itself does: that
|
||||
raw LoRa frames which are decoded are intact, but not all frames will
|
||||
be received. It is somewhat akin to UDP in this sense. Protocols
|
||||
such as UUCP, ZModem, or TCP can be layered atop **lorapipe** to
|
||||
transform this into a "reliable" connection.
|
||||
When running in **xbnet tap** mode, it is simulating an Ethernet interface. Every Ethernet packet has a source and destination MAC address. xbnet will maintain a cache of the Ethernet MAC addresses it has seen and what XBee MAC address they came from. Therefore, when it sees a request to transmit to a certain Ethernet MAC, it will reuse what it knows from its cache and direct the packet to the appropriate XBee destination. Ethernet broadcasts are converted into XBee broadcasts.
|
||||
|
||||
## Broadcast Use and Separate Frequencies
|
||||
|
||||
It is quite possible to use **lorapipe** to broadcast data to multiple
|
||||
listeners; an unlimited number of systems can run **lorapipe pipe**
|
||||
to receive data, and as long as there is nothing on stdin, they will
|
||||
happily decode data received over the air without transmitting
|
||||
anything.
|
||||
|
||||
Separate communication channels may be easily achieved by selecting
|
||||
separate radio frequencies.
|
||||
|
||||
## Collision Mitigation
|
||||
|
||||
**lorapipe** cannot provide collision detection or avoidance, though
|
||||
it does impliement a collision mitigation strategy as described below.
|
||||
|
||||
As LoRa radios are half-duplex (they cannot receive while
|
||||
transmitting), this poses challenges for quite a few applications that
|
||||
expect full-duplex communication or something like it. In testing, a
|
||||
particular problem was observed with protocols that use transmission
|
||||
windows and send data in packets. These protocols send ACKs after a
|
||||
successful packet transmission, which frequently collided with the
|
||||
next packet transmitted from the other radio. This caused serious
|
||||
performance degredations, and for some protocols, complete failure.
|
||||
|
||||
There is no carrier detect signal from the LoRa radio. Therefore, a
|
||||
turn-based mechanism is implemented; with each frame transmitted, a
|
||||
byte is prepended indicating whether the sender has more data in queue
|
||||
to transmit or not. The sender will continue transmitting until its
|
||||
transmit buffer is empty. When that condition is reached, the
|
||||
other end will begin transmitting whatever is in its queue. This
|
||||
enables protocols such as UUCP "g" and UUCP "i" to work quite well.
|
||||
|
||||
A potential complication could arise if the "last" packet from the
|
||||
transmitter never arrives at the receiver; the receiver might
|
||||
therefore never take a turn to transmit. To guard against this
|
||||
possibility, there is a timer, and after receiving no packets for a
|
||||
certain amount of time, the receiver will assume it is acceptable to
|
||||
transmit. This timeout is set by the **--eotwait** option and
|
||||
defaults to 1000ms (1 second).
|
||||
|
||||
The signal about whether or not data remains in the queue takes the
|
||||
form of a single byte prepended to every frame. It is 0x00 if no data
|
||||
will follow immediately, and 0x01 if data exists in the transmitters
|
||||
queue which will be sent immediately. The receiving side processes
|
||||
this byte and strips it off before handing the data to the
|
||||
application. This byte is, however, visible under **--debug** mode,
|
||||
so you can observe the protocol at this low level.
|
||||
The **xbnet tun** mode operates in a similar fashion; it keeps a cache of seen IP addresses and their corresponding XBee MAC addresses, and directs packets appropriately.
|
||||
|
||||
# RADIO PARAMETERS AND INITIALIZATION
|
||||
|
||||
The Microchip command reference, available at
|
||||
<http://ww1.microchip.com/downloads/en/DeviceDoc/40001811A.pdf>,
|
||||
describes the parameters available for the radio. A LoRa data rate
|
||||
calculator is available at
|
||||
<https://www.rfwireless-world.com/calculators/LoRa-Data-Rate-Calculator.html>
|
||||
to give you a rough sense of the speed of different parameters. In
|
||||
general, by sacrificing speed, you can increase range and robustness
|
||||
of the signal. The default initialization uses fairly slow and
|
||||
high-range settings:
|
||||
|
||||
```
|
||||
sys get ver
|
||||
mac reset
|
||||
mac pause
|
||||
radio get mod
|
||||
radio get freq
|
||||
radio get pwr
|
||||
radio get sf
|
||||
radio get bw
|
||||
radio get cr
|
||||
radio get wdt
|
||||
radio set pwr 20
|
||||
radio set sf sf12
|
||||
radio set bw 125
|
||||
radio set cr 4/5
|
||||
radio set wdt 60000
|
||||
```
|
||||
|
||||
The `get` commands will cause the pre-initialization settings to be
|
||||
output to stderr if `--debug` is used. A maximum speed init would
|
||||
look like this:
|
||||
|
||||
```
|
||||
sys get ver
|
||||
mac reset
|
||||
mac pause
|
||||
radio get mod
|
||||
radio get freq
|
||||
radio get pwr
|
||||
radio get sf
|
||||
radio get bw
|
||||
radio get cr
|
||||
radio get wdt
|
||||
radio set pwr 20
|
||||
radio set sf sf7
|
||||
radio set bw 500
|
||||
radio set cr 4/5
|
||||
radio set wdt 60000
|
||||
```
|
||||
|
||||
You can craft your own parameters and pass them in with `--initfile`
|
||||
to customize the performance of your RF link.
|
||||
|
||||
A particular hint: if `--debug` shows `radio_err` after a `radio rx 0`
|
||||
command, the radio is seeing carrier but is getting CRC errors
|
||||
decoding packets. Increasing the code rate with `radio set cr` to a
|
||||
higher value such as `4/6` or even `4/8` will increase the FEC
|
||||
redundancy and enable it to decode some of those packets. Increasing
|
||||
code rate will not help if there is complete silence from the radio
|
||||
during a transmission; for those situations, try decreasing bandwidth
|
||||
or increasing the spreading factor. Note that coderate `4/5` to the
|
||||
radio is the same as `1` to the calculator, while `4/8` is the same as
|
||||
`4`.
|
||||
|
||||
**Important note**: If you have the RN2483-based Lorastik, it requires
|
||||
a band as part of the `mac reset` command. You will need to edit the
|
||||
config file to say either `mac reset 868` or `mac reset 433` depending
|
||||
on which band you will be using. See
|
||||
<https://github.com/jgoerzen/lorapipe/issues/2> for further details.
|
||||
|
||||
# PROTOCOL HINTS
|
||||
|
||||
Although **lorapipe pipe** doesn't guarantee it preserves application
|
||||
framing, in many cases it does. For applications that have their own
|
||||
framing, it is highly desirable to set their frame size to be less
|
||||
than the **--maxpacketsize** setting. This will
|
||||
reduce the amount of data that would have to be retransmitted due to
|
||||
lost frames.
|
||||
|
||||
As speed decreases, packet size should as well.
|
||||
This program requires API mode from the board. It will perform that initialization automatically. Additional configurations may be added by you using the **--initfile** option.
|
||||
|
||||
# APPLICATION HINTS
|
||||
|
||||
## FULL TCP/IP USING TUN
|
||||
|
||||
This is the marquee feature of xbnet. It provides a full TCP/IP stack across the XBee links, supporting both IPv4 and IPv6. You can do anything you wish with the participating nodes in your mesh: ping, ssh, route the Internet across them, etc. Up to you! A Raspberry Pi with wifi and xbnet could provide an Internet gateway for an entire XBee mesh, if you so desire.
|
||||
|
||||
This works by creating a virtual network device in Linux, called a "tun" device. Traffic going out that device will be routed onto XBee, and traffic coming in will be routed to the computer.
|
||||
|
||||
## TRANSPARENT MODE
|
||||
|
||||
XBee systems have a "transparent mode" in which you can configure a particular destination and use them as a raw serial port. You should definitely consider if this meets your needs for serial-based protocols; it would eliminate xbnet from the path entirely.
|
||||
|
||||
However, you may still wish to use xbnet; perhaps for its debugging. Also there are some scenarios (such at TCP/IP with multiple destinations) that really cannot be done in transparent mode -- and that is what xbnet is for, and where it shines.
|
||||
|
||||
## SOCAT
|
||||
|
||||
The **socat**(1) program can be particularly helpful; it can gateway TCP
|
||||
ports and various other sorts of things into **lorapipe**. This is
|
||||
helpful if the **lorapipe** system is across a network from the system
|
||||
ports and various other sorts of things into **xbnet**. This is
|
||||
helpful if the **xbnet** system is across a network from the system
|
||||
you wish to run an application on. **ssh**(1) can also be useful for
|
||||
this purpose.
|
||||
|
||||
A basic command might be like this:
|
||||
|
||||
```
|
||||
socat TCP-LISTEN:12345 EXEC:'lorapipe /dev/ttyUSB0 pipe,pty,rawer'
|
||||
socat TCP-LISTEN:12345 EXEC:'xbnet /dev/ttyUSB0 pipe --dest=1234,pty,rawer'
|
||||
```
|
||||
|
||||
Some systems might require disabling buffering in some situations, or
|
||||
using a pty. In those instances, something like this may be in order:
|
||||
|
||||
```
|
||||
socat TCP-LISTEN:10104 EXEC:'stdbuf -i0 -o0 -e0 lorapipe /dev/ttyUSB4 pipe,pty,rawer'
|
||||
socat TCP-LISTEN:10104 EXEC:'stdbuf -i0 -o0 -e0 xbnet /dev/ttyUSB4 pipe --dest=1234,pty,rawer'
|
||||
```
|
||||
|
||||
## UUCP
|
||||
|
||||
For UUCP, I recommend protocol `i` with the default window-size
|
||||
setting. Use as large of a packet size as you can; for slow links,
|
||||
perhaps 32, up to around 100 for fast, high-quality links. (LoRa seems to
|
||||
not do well with packets above 100 bytes).
|
||||
perhaps 32, up to around 244 for fast, high-quality links.
|
||||
|
||||
Protocol `g` (or `G` with a smaller packet size) can also work, but
|
||||
won't work as well.
|
||||
|
@ -236,9 +94,9 @@ protocol-parameter i timeout 30
|
|||
chat-timeout 60
|
||||
```
|
||||
|
||||
Note that UUCP protocol i adds 10 bytes of overhead per packet, so
|
||||
Note that UUCP protocol i adds 10 bytes of overhead per packet and xbnet adds 1 byte of overhead, so
|
||||
this is designed to work with the default recommended packet size of
|
||||
100.
|
||||
255.
|
||||
|
||||
Then in `/etc/uucp/port`:
|
||||
|
||||
|
@ -249,19 +107,20 @@ reliable false
|
|||
|
||||
## YMODEM (and generic example of bidirectional pipe)
|
||||
|
||||
ZModem makes a poor fit for LoRa because its smallest block size is
|
||||
1K. YModem, however, uses a 128-byte block size. Here's an example
|
||||
ZModem makes a good fit for the higher bitrate XBee modules. For the slower settings, consider YModem; its 128-byte block size may be more suitable for very slow links than ZModem's 1K.
|
||||
|
||||
Here's an example
|
||||
of how to make it work. Let's say we want to transmit /bin/true over
|
||||
the radio. We could run this:
|
||||
|
||||
```
|
||||
socat EXEC:'sz --ymodem /bin/true' EXEC:'lorapipe /dev/ttyUSB0 pipe,pty,rawer'
|
||||
socat EXEC:'sz --ymodem /bin/true' EXEC:'xbnet /dev/ttyUSB0 pipe --dest=1234,pty,rawer'
|
||||
```
|
||||
|
||||
And on the receiving end:
|
||||
|
||||
```
|
||||
socat EXEC:'rz --ymodem' EXEC:'lorapipe /dev/ttyUSB0 pipe,pty,rawer'
|
||||
socat EXEC:'rz --ymodem' EXEC:'xbnet /dev/ttyUSB0 pipe --dest=5678,pty,rawer'
|
||||
```
|
||||
|
||||
This approach can also be used with many other programs. For
|
||||
|
@ -270,11 +129,9 @@ instance, `uucico -l` for UUCP logins.
|
|||
## KERMIT
|
||||
|
||||
Using the C-kermit distribution (**apt-get install ckermit**), you can
|
||||
configure for **lorapipe** like this:
|
||||
configure for **xbnet** like this:
|
||||
|
||||
```
|
||||
set receive packet-length 90
|
||||
set send packet-length 90
|
||||
set duplex half
|
||||
set window 2
|
||||
set receive timeout 10
|
||||
|
@ -284,7 +141,7 @@ set send timeout 10
|
|||
Then, on one side, run:
|
||||
|
||||
```
|
||||
pipe lorapipe /dev/ttyUSB0 pipe
|
||||
pipe xbnet /dev/ttyUSB0 pipe --dest=1234
|
||||
Ctrl-\ c
|
||||
server
|
||||
```
|
||||
|
@ -292,7 +149,7 @@ server
|
|||
And on the other:
|
||||
|
||||
```
|
||||
pipe lorapipe /dev/ttyUSB0 pipe
|
||||
pipe xbnet /dev/ttyUSB0 pipe --dest=5678
|
||||
Ctrl-\ c
|
||||
```
|
||||
|
||||
|
@ -304,23 +161,23 @@ Now you can do things like `rdir` (to see ls from the remote), `get`,
|
|||
To interact directly with the modem, something like this will work:
|
||||
|
||||
```
|
||||
cu -h --line /dev/ttyUSB0 -s 57600 -e -o -f --nostop
|
||||
cu -h --line /dev/ttyUSB0 -s 9600 -e -o --nostop
|
||||
```
|
||||
|
||||
# RUNNING TCP/IP OVER LORA WITH PPP
|
||||
# RUNNING TCP/IP OVER XBEE WITH PPP
|
||||
|
||||
PPP is the fastest way to run TCP/IP over LoRa with **lorapipe**. It
|
||||
PPP is the fastest way to run TCP/IP over XBee with **xbnet** - and can work in transparent mode without xbnet as well. It
|
||||
is subject to a few limitations:
|
||||
|
||||
- At most two devices must be using the frequency. PPP cannot support
|
||||
ad-hoc communication to multiple devices like AX.25 can (see below).
|
||||
- PPP cannot support
|
||||
ad-hoc communication to multiple devices. It is strictly point-to-point between two devices.
|
||||
- PPP compression should not be turned on. This is because PPP
|
||||
normally assumes a lossless connection, and any dropped packets
|
||||
become rather expensive for PPP to handle, since compression has to
|
||||
be re-set. Better to use compression at the protocol level; for
|
||||
instance, with **ssh -C**.
|
||||
|
||||
To set up PPP, on one device, create /etc/ppp/peers/lora with this
|
||||
To set up PPP, on one device, create /etc/ppp/peers/xbee with this
|
||||
content:
|
||||
|
||||
```
|
||||
|
@ -342,7 +199,7 @@ Now, fire it up on each end with a command like this:
|
|||
|
||||
```
|
||||
socat EXEC:'pppd nodetach file /etc/ppp/peers/lora,pty,rawer' \
|
||||
EXEC:'lorapipe --txslot 2000 --initfile=init-fast.txt --maxpacketsize 100 --txwait 120 /dev/ttyUSB0 pipe,pty,rawer'
|
||||
EXEC:'xbnet --initfile=init-fast.txt /dev/ttyUSB0 pipe --dest=1234,pty,rawer'
|
||||
```
|
||||
|
||||
According to the PPP docs, an MRU of 296 might be suitable for slower
|
||||
|
@ -350,74 +207,11 @@ links.
|
|||
|
||||
This will now permit you to ping across the link. Additional options
|
||||
can be added to add, for instance, a bit of authentication at the
|
||||
start and so forth (though note that LoRa, being RF, means that a
|
||||
start and so forth (though note that XBee, being RF, means that a
|
||||
session could be hijacked, so don't put a lot of stock in this as a
|
||||
limit; best to add firewall rules, etc.)
|
||||
|
||||
Of course, ssh can nicely run over this, and in my testing, PPP was
|
||||
the fastest method of running SSH over LoRa, beating out even AX.25.
|
||||
But then, that makes some sense, since AX.25 has to add addressing
|
||||
bits to every frame since it is a more LAN-like protocol.
|
||||
|
||||
# RUNNING SSH AND/OR TCP/IP OVER AX.25 WITH KISS
|
||||
|
||||
The AX.25 protocol was initially designed to be used for amateur radio
|
||||
purposes. As the original amateur radio systems have a number of
|
||||
properties in common with LoRa, it makes a reasonable way to run a
|
||||
TCP/IP stack atop LoRa. **lorapipe** supports it via the [KISS
|
||||
protocol](http://www.ax25.net/kiss.aspx), which is similar to PPP for
|
||||
AX.25.
|
||||
|
||||
PPP normally assumes a reliable, point-to-point connection. AX.25 and
|
||||
KISS allow for more than 2 devices to share a frequency.
|
||||
|
||||
|
||||
These instructions assume Debian or Raspbian. Other operating systems
|
||||
may be different.
|
||||
|
||||
First, install the AX.25 tools: `apt-get install ax25-tools
|
||||
ax25-apps socat`.
|
||||
|
||||
Now, edit `/etc/ax25/axports` and add a line such as:
|
||||
|
||||
```
|
||||
lora NODE1 1200 70 1 lorapipe radio
|
||||
```
|
||||
|
||||
This defines a port named **lora**, with fake "callsign" **NODE1**,
|
||||
speed 1200 (which is ignored), maximum packet length 70, and
|
||||
window 1. Keep the packet length less than the **--maxpacketsize**.
|
||||
It is possible that KISS frames may expand due to escaping;
|
||||
**lorapipe** will fragment them in this case, but it is best to keep
|
||||
this size significantly less than the **lorapipe** max packet size to
|
||||
avoid fragmentation as much as possible. On other machines, give them
|
||||
unique callsigns (NODE2 or FOO1 or whatever you like).
|
||||
|
||||
Now, start KISS:
|
||||
|
||||
```
|
||||
kissattach /dev/ptmx lora 192.168.2.2
|
||||
AX.25 port lora bound to device ax0
|
||||
Awaiting client connects on
|
||||
/dev/pts/7
|
||||
```
|
||||
|
||||
That IP address was made up; you can use any RFC1918 IP address here;
|
||||
just make sure they're different on each node.
|
||||
|
||||
It says to connect to /dev/pts/7, so we'll do just that:
|
||||
|
||||
```
|
||||
socat /dev/pts/7,rawer \
|
||||
EXEC:'lorapipe /dev/ttyUSB0 kiss,pty,rawer'
|
||||
```
|
||||
|
||||
Now, assume you connected a second machine to 192.168.2.3, you should
|
||||
be able to ping and talk back and forth between them. Standard
|
||||
commands will work at this stage. You may wish to adjust the packet
|
||||
size in /etc/axports up from 70.
|
||||
|
||||
To bring down the link, Ctrl-C the socat sessions and run `killall kissattach`.
|
||||
Of course, ssh can nicely run over this, but for more versatility, consider the tap or tun options.
|
||||
|
||||
## OPTIMIZING TCP/IP OVER LORA
|
||||
|
||||
|
@ -427,7 +221,7 @@ is a significant overhead. It can be dramatically reduced by using a
|
|||
larger packet size; for instance, in /etc/ax25/axports, thange the
|
||||
packet length of 70 to 1024. This will now cause the
|
||||
**--maxpacketsize** option to take precedence and fragment the TCP/IP
|
||||
packets for transmission over LoRa; they will, of course, be
|
||||
packets for transmission over XBee; they will, of course, be
|
||||
reassembled on the other end. Setting **--txslot 2000** or a similar
|
||||
value will also be helpful in causing TCP ACKs to reach the remote end
|
||||
quicker, hopefully before timeouts expire. **--pack** may also
|
||||
|
@ -436,71 +230,21 @@ produce some marginal benefit.
|
|||
I have been using:
|
||||
|
||||
```
|
||||
lorapipe --initfile=init-fast.txt --txslot 2000 --pack --debug --maxpacketsize 200 --txwait 150
|
||||
xbnet --initfile=init-fast.txt --txslot 2000 --pack --debug --maxpacketsize 200 --txwait 150
|
||||
```
|
||||
|
||||
with success on a very clean (reasonably error-free) link.
|
||||
|
||||
## More on Linux AX.25
|
||||
|
||||
For more information, see:
|
||||
|
||||
- [The Linux AX.25 HOWTO](http://www.tldp.org/HOWTO/AX25-HOWTO/)
|
||||
|
||||
## SSH OVER AX.25 WITHOUT TCP/IP
|
||||
|
||||
Before **lorapipe** introduced frame combining and **--txslot**,
|
||||
performance of SSH over TCP/IP was as low as 25% of its performance
|
||||
over native AX.25. With the addition of the above features, it has
|
||||
achieved parity with native AX.25 on fairly clean links.
|
||||
|
||||
There is somewhat more effort on running SSH atop AX.25 natively,
|
||||
since it was not designed to run in such a way. We can make it work,
|
||||
however.
|
||||
|
||||
First, on the node which will run the SSH server -- in this example it
|
||||
will be NODE1 -- create an /etc/ax25/ax25d.conf file with contents
|
||||
like this:
|
||||
|
||||
```[NODE1-1 VIA *]
|
||||
NOCALL * * * * * * L
|
||||
default * * * * * * - root /usr/bin/socat socat -b 220 STDIO TCP:localhost:22
|
||||
```
|
||||
|
||||
This will cause it to accept connections on AX.25 port 1 (in NODE1-1,
|
||||
the part after the dash is the AX.25 port number), and redirect to
|
||||
local TCP port 22, ssh. The -b 220 assumes the packet length is 220
|
||||
in /etc/ax25/axports, and causes ssh data to not exceed that length.
|
||||
|
||||
Now you can fire it up with **ax25d -l**.
|
||||
|
||||
Connecting to it requires an 8-bit clean AX.25 connection.
|
||||
Unfortunately, **axcall(1)** does not provide this. **ax25_call**
|
||||
can, but it must be modified to cause it to not emit the
|
||||
"Connecting..." and "Connected" messages which will confuse ssh. Once
|
||||
done, the connection can be initiated with:
|
||||
|
||||
```
|
||||
ssh -v -o "ProxyCommand=socat -b 220 STDIO EXEC:'/path/ax25_call -i 220 -o 220 lora NODE2 NODE1-1,pty,rawer'" user@host
|
||||
```
|
||||
|
||||
NODE2 is the node name that ssh is running on, and NODE1 is the
|
||||
destination node. Replace every instance of 220 here with your
|
||||
maximum packet length.
|
||||
|
||||
This is a somewhat fragile setup, and it is recommended to use TCP
|
||||
instead, in general.
|
||||
|
||||
# INSTALLATION
|
||||
|
||||
**lorapipe** is a Rust program and can be built by running **`cargo
|
||||
**xbnet** is a Rust program and can be built by running **`cargo
|
||||
build --release`**. The executable will then be placed in
|
||||
**target/release/lorapipe**. Rust can be easily installed from
|
||||
**target/release/xbnet**. Rust can be easily installed from
|
||||
<https://www.rust-lang.org/>.
|
||||
|
||||
# INVOCATION
|
||||
|
||||
Every invocation of **lorapipe** requires at least the name of a
|
||||
Every invocation of **xbnet** requires at least the name of a
|
||||
serial port (for instance, **/dev/ttyUSB0**) and a subcommand to run.
|
||||
|
||||
# GLOBAL OPTIONS
|
||||
|
@ -519,7 +263,7 @@ before the port and command on the command line.
|
|||
: Attempt to read and log information about the RF quality of
|
||||
incoming packets after each successful packet received. There are
|
||||
some corner cases where this is not possible. The details will be
|
||||
logged with **lorapipe**'s logging facility, and are therefore only
|
||||
logged with **xbnet**'s logging facility, and are therefore only
|
||||
visible if **--debug** is also used.
|
||||
|
||||
**--pack**
|
||||
|
@ -531,7 +275,7 @@ before the port and command on the command line.
|
|||
much data as possible into each.
|
||||
|
||||
**-V**, **--version**
|
||||
: Display the version number of **lorapipe**.
|
||||
: Display the version number of **xbnet**.
|
||||
|
||||
**--eotwait** *TIME*
|
||||
: The amount of time in milliseconds to wait after receiving a packet
|
||||
|
@ -576,8 +320,8 @@ before the port and command on the command line.
|
|||
**--maxpacketsize** *BYTES*
|
||||
: The maximum frame size, in the range of 10 - 250. The actual frame
|
||||
transmitted over the air will be one byte larger due to
|
||||
**lorapipe** collision mitigation as described above.
|
||||
Experimentation myself, and reports from others, suggests that LoRa
|
||||
**xbnet** collision mitigation as described above.
|
||||
Experimentation myself, and reports from others, suggests that XBee
|
||||
works best when this is 100 or less.
|
||||
|
||||
*PORT*
|
||||
|
@ -588,22 +332,22 @@ before the port and command on the command line.
|
|||
|
||||
# SUBCOMMANDS
|
||||
|
||||
## lorapipe ... pipe
|
||||
## xbnet ... pipe
|
||||
|
||||
The **pipe** subcommand is the main workhorse of the application and
|
||||
is described extensively above.
|
||||
|
||||
## lorapipe ... ping
|
||||
## xbnet ... ping
|
||||
|
||||
The **ping** subcommand will transmit a simple line of text every 10
|
||||
seconds including an increasing counter. It can be displayed at the
|
||||
other end with **lorapipe ... pipe** or reflected with **lorapipe
|
||||
other end with **xbnet ... pipe** or reflected with **xbnet
|
||||
... pong**.
|
||||
|
||||
## lorapipe ... pong
|
||||
## xbnet ... pong
|
||||
|
||||
The **pong** subcommand receives packets and crafts a reply. It is
|
||||
intended to be used with **lorapipe ... ping**. Its replies include
|
||||
intended to be used with **xbnet ... ping**. Its replies include
|
||||
the signal quality SNR and RSSI if available.
|
||||
|
||||
# AUTHOR
|
||||
|
|
23
src/main.rs
23
src/main.rs
|
@ -50,10 +50,14 @@ struct Opt {
|
|||
#[structopt(long, parse(from_os_str))]
|
||||
initfile: Option<PathBuf>,
|
||||
|
||||
#[structopt(parse(from_os_str))]
|
||||
/// Serial port to use to communicate with radio
|
||||
#[structopt(parse(from_os_str))]
|
||||
port: PathBuf,
|
||||
|
||||
/// The speed in bps (baud rate) to use to communicate on the serial port
|
||||
#[structopt(long, default_value = "9600")]
|
||||
serial_speed: u32,
|
||||
|
||||
/// Disable the Xbee-level ACKs
|
||||
#[structopt(long)]
|
||||
disable_xbee_acks: bool,
|
||||
|
@ -114,6 +118,15 @@ enum Command {
|
|||
/// at startup.
|
||||
#[structopt(long, default_value = "xbnet%d")]
|
||||
iface_name: String,
|
||||
|
||||
/// Disable all IPv4 support
|
||||
#[structopt(long)]
|
||||
disable_ipv4: bool,
|
||||
|
||||
/// Disable all IPv6 support
|
||||
#[structopt(long)]
|
||||
disable_ipv6: bool,
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -126,7 +139,7 @@ fn main() {
|
|||
}
|
||||
info!("xbnet starting");
|
||||
|
||||
let (ser_reader, ser_writer) = ser::new(opt.port).expect("Failed to initialize serial port");
|
||||
let (ser_reader, ser_writer) = ser::new(opt.port, opt.serial_speed).expect("Failed to initialize serial port");
|
||||
let (mut xb, xbeesender, writerthread) = xb::XB::new(
|
||||
ser_reader,
|
||||
ser_writer,
|
||||
|
@ -176,7 +189,6 @@ fn main() {
|
|||
)
|
||||
.expect("Failure initializing tap");
|
||||
let tap_writer = tap_reader.clone();
|
||||
let maxpacketsize = xb.maxpacketsize;
|
||||
thread::spawn(move || {
|
||||
tap_writer
|
||||
.frames_from_xb_processor(&mut xbreframer, &mut xb.ser_reader)
|
||||
|
@ -192,13 +204,14 @@ fn main() {
|
|||
broadcast_everything,
|
||||
iface_name,
|
||||
max_ip_cache,
|
||||
disable_ipv4,
|
||||
disable_ipv6,
|
||||
} => {
|
||||
let max_ip_cache = Duration::from_secs(max_ip_cache);
|
||||
let tun_reader =
|
||||
tun::XBTun::new_tun(xb.mymac, broadcast_everything, iface_name, max_ip_cache)
|
||||
tun::XBTun::new_tun(xb.mymac, broadcast_everything, iface_name, max_ip_cache, disable_ipv4, disable_ipv6)
|
||||
.expect("Failure initializing tun");
|
||||
let tun_writer = tun_reader.clone();
|
||||
let maxpacketsize = xb.maxpacketsize;
|
||||
thread::spawn(move || {
|
||||
tun_writer
|
||||
.frames_from_xb_processor(&mut xbreframer, &mut xb.ser_reader)
|
||||
|
|
|
@ -35,9 +35,9 @@ pub struct XBSerWriter {
|
|||
}
|
||||
|
||||
/// Initialize the serial system, configuring the port.
|
||||
pub fn new(portname: PathBuf) -> io::Result<(XBSerReader, XBSerWriter)> {
|
||||
pub fn new(portname: PathBuf, speed: u32) -> io::Result<(XBSerReader, XBSerWriter)> {
|
||||
let settings = SerialPortSettings {
|
||||
baud_rate: 115200, // FIXME: make this configurable, default 9600
|
||||
baud_rate: speed,
|
||||
data_bits: DataBits::Eight,
|
||||
flow_control: FlowControl::Hardware,
|
||||
parity: Parity::None,
|
||||
|
|
31
src/tun.rs
31
src/tun.rs
|
@ -43,6 +43,8 @@ pub struct XBTun {
|
|||
pub broadcast_everything: bool,
|
||||
pub tun: Arc<Iface>,
|
||||
pub max_ip_cache: Duration,
|
||||
pub disable_ipv4: bool,
|
||||
pub disable_ipv6: bool,
|
||||
|
||||
/** The map from IP Addresses (v4 or v6) to destination MAC addresses. Also
|
||||
includes a timestamp at which the destination expires. */
|
||||
|
@ -55,6 +57,8 @@ impl XBTun {
|
|||
broadcast_everything: bool,
|
||||
iface_name_requested: String,
|
||||
max_ip_cache: Duration,
|
||||
disable_ipv4: bool,
|
||||
disable_ipv6: bool,
|
||||
) -> io::Result<XBTun> {
|
||||
let tun = Iface::without_packet_info(&iface_name_requested, Mode::Tun)?;
|
||||
let name = tun.name();
|
||||
|
@ -67,6 +71,8 @@ impl XBTun {
|
|||
myxbmac,
|
||||
broadcast_everything,
|
||||
max_ip_cache,
|
||||
disable_ipv4,
|
||||
disable_ipv6,
|
||||
name: String::from(name),
|
||||
tun: Arc::new(tun),
|
||||
dests: Arc::new(Mutex::new(desthm)),
|
||||
|
@ -110,6 +116,19 @@ impl XBTun {
|
|||
Ok(packet) => {
|
||||
let ips = extract_ips(&packet);
|
||||
if let Some((source, destination)) = ips {
|
||||
match destination {
|
||||
IpAddr::V6(_) =>
|
||||
if self.disable_ipv6 {
|
||||
debug!("Dropping packet because --disable-ipv6 given");
|
||||
return Ok(());
|
||||
},
|
||||
IpAddr::V4(_) =>
|
||||
if self.disable_ipv4 {
|
||||
debug!("Dropping packet because --disable-ipv4 given");
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
let destxbmac = self.get_xb_dest_mac(&destination);
|
||||
trace!(
|
||||
"TAPIN: Packet {} -> {} (MAC {:x})",
|
||||
|
@ -156,6 +175,18 @@ impl XBTun {
|
|||
let ips = extract_ips(&packet);
|
||||
if let Some((source, destination)) = ips {
|
||||
trace!("SERIN: Packet is {} -> {}", source, destination);
|
||||
match source {
|
||||
IpAddr::V6(_) =>
|
||||
if self.disable_ipv6 {
|
||||
debug!("Dropping packet because --disable-ipv6 given");
|
||||
return Ok(());
|
||||
},
|
||||
IpAddr::V4(_) =>
|
||||
if self.disable_ipv4 {
|
||||
debug!("Dropping packet because --disable-ipv4 given");
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
if !self.broadcast_everything {
|
||||
self.dests.lock().unwrap().insert(
|
||||
source,
|
||||
|
|
Loading…
Reference in New Issue