1. Add WFB-NG std draft.

2. Fix frame format.
3. Add multiple links support
4. Add missing libsodium init. Warn if not enough entropy is available
5. Add project logo
This commit is contained in:
Vasily Evseenko 2022-09-08 21:28:30 +03:00
parent 3ff62387e6
commit 73af6d7cfa
26 changed files with 1413 additions and 151 deletions

View File

@ -13,7 +13,7 @@ all: all_bin gs.key test
env:
virtualenv env --python=$(PYTHON)
./env/bin/pip install --upgrade pip==20.2.3 setuptools==44.1.1 stdeb
./env/bin/pip install --upgrade pip setuptools stdeb
all_bin: wfb_rx wfb_tx wfb_keygen

View File

@ -1,5 +1,5 @@
WFB-NG
=============
![WFB-NG](doc/logo-big-1280x640.png)
This is the next generation of long-range **packet** radio link based on **raw WiFi radio**

4
doc/Makefile Normal file
View File

@ -0,0 +1,4 @@
all: wfb-ng-std-draft.html
%.html: %.md
pandoc --self-contained -V include-before='<style>body {max-width:unset!important}</style>' --from markdown $^ -o $@

BIN
doc/logo-big-1280x640.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

442
doc/logo-big.eps Normal file
View File

@ -0,0 +1,442 @@
%!PS-Adobe-3.0 EPSF-3.0
%%Creator: cairo 1.15.10 (http://cairographics.org)
%%CreationDate: Wed Sep 7 10:35:40 2022
%%Pages: 1
%%DocumentData: Clean7Bit
%%LanguageLevel: 2
%%BoundingBox: 22 0 794 261
%%EndComments
%%BeginProlog
50 dict begin
/q { gsave } bind def
/Q { grestore } bind def
/cm { 6 array astore concat } bind def
/w { setlinewidth } bind def
/J { setlinecap } bind def
/j { setlinejoin } bind def
/M { setmiterlimit } bind def
/d { setdash } bind def
/m { moveto } bind def
/l { lineto } bind def
/c { curveto } bind def
/h { closepath } bind def
/re { exch dup neg 3 1 roll 5 3 roll moveto 0 rlineto
0 exch rlineto 0 rlineto closepath } bind def
/S { stroke } bind def
/f { fill } bind def
/f* { eofill } bind def
/n { newpath } bind def
/W { clip } bind def
/W* { eoclip } bind def
/BT { } bind def
/ET { } bind def
/BDC { mark 3 1 roll /BDC pdfmark } bind def
/EMC { mark /EMC pdfmark } bind def
/cairo_store_point { /cairo_point_y exch def /cairo_point_x exch def } def
/Tj { show currentpoint cairo_store_point } bind def
/TJ {
{
dup
type /stringtype eq
{ show } { -0.001 mul 0 cairo_font_matrix dtransform rmoveto } ifelse
} forall
currentpoint cairo_store_point
} bind def
/cairo_selectfont { cairo_font_matrix aload pop pop pop 0 0 6 array astore
cairo_font exch selectfont cairo_point_x cairo_point_y moveto } bind def
/Tf { pop /cairo_font exch def /cairo_font_matrix where
{ pop cairo_selectfont } if } bind def
/Td { matrix translate cairo_font_matrix matrix concatmatrix dup
/cairo_font_matrix exch def dup 4 get exch 5 get cairo_store_point
/cairo_font where { pop cairo_selectfont } if } bind def
/Tm { 2 copy 8 2 roll 6 array astore /cairo_font_matrix exch def
cairo_store_point /cairo_font where { pop cairo_selectfont } if } bind def
/g { setgray } bind def
/rg { setrgbcolor } bind def
/d1 { setcachedevice } bind def
/cairo_data_source {
CairoDataIndex CairoData length lt
{ CairoData CairoDataIndex get /CairoDataIndex CairoDataIndex 1 add def }
{ () } ifelse
} def
/cairo_flush_ascii85_file { cairo_ascii85_file status { cairo_ascii85_file flushfile } if } def
/cairo_image { image cairo_flush_ascii85_file } def
/cairo_imagemask { imagemask cairo_flush_ascii85_file } def
%%EndProlog
%%BeginSetup
%%BeginResource: font GOST-2.304-81typeB
11 dict begin
/FontType 42 def
/FontName /GOST-2.304-81typeB def
/PaintType 0 def
/FontMatrix [ 1 0 0 1 0 0 ] def
/FontBBox [ 0 0 0 0 ] def
/Encoding 256 array def
0 1 255 { Encoding exch /.notdef put } for
Encoding 45 /hyphen put
Encoding 66 /B put
Encoding 68 /D put
Encoding 70 /F put
Encoding 76 /L put
Encoding 87 /W put
Encoding 97 /a put
Encoding 103 /g put
Encoding 105 /i put
Encoding 107 /k put
Encoding 110 /n put
Encoding 116 /t put
/CharStrings 13 dict dup begin
/.notdef 0 def
/W 1 def
/F 2 def
/B 3 def
/hyphen 4 def
/n 5 def
/g 6 def
/D 7 def
/a 8 def
/t 9 def
/L 10 def
/i 11 def
/k 12 def
end readonly def
/sfnts [
<000100000009008000030010637674200403004500000528000000146670676dc960b19b0000
053c00000153676c79662c7c13ec0000009c0000048c68656164cf259b670000069000000036
6868656108a904db000006c800000024686d747818a3034f000006ec000000346c6f63610762
0888000007200000001c6d617870021f01c30000073c0000002070726570e9ab85350000075c
0000002f0002001f000001d50379000300070018400d040002070300060603030207032b2b00
3f2b10dc303133211121012111211f01b6fe4a0197fe8801780379fca6033b00000000010044
ffff02ac02ac0022000001363534262322070b01262322070b01262322061514171316333236
371b011633323702ab01160e1a0670600a16160a616f061b0d160189061b0a1204696909171a
07028202060f131bfe0c01091c1cfef701f41b130e0702fd991c0d0b011ffee1181c00000001
00440000019a02ac001a00001335333236353426232122151114163332363511333236353426
2389ef10121111feef23150e0f13ef10121111019bcc150d0f1423fd99101211110134150e0f
130000030044000001de02ac0015001f0029000001363d013427262b01221511143b01323736
3d013426053332161d0114062b011323353332161d011406019d1f282739cd2323ef39272822
fecdcd1c28281ccdababab1c2828018625334539282823fd992227283a88263d1e281d881d28
0156cd271d451c280001004400cd019a0111000d000025323635342623212206151416330178
10121111feef11121310cd150d0f13140e0e14000000000100440000019a01de001a00002511
3427262b012215111416333236351133321615111416333236019a28273aaa23150e0f13881d
28140e0f1322013439282722fe66101211110178281cfecc10121100000000020044ff33019a
01de000900260000252322263d0134363b01111514062b0122061514163b013237363511342b
0122061d01141716330156891d27271d89281d8811111210883a282722ab395028283944281d
cd1c28fe66441d28140e0e1428273a0200225038cd3a282700020044000001de02ac000f0019
000025113427262b01221511143b013237362714062b01113332161501de282739ef2323ef39
272844281ccdcd1c2889019a39282823fd992227283a1d280223271d00020044ffff01df01de
000c002800002514062b0122263d0134363b01131617163332363534272e013511342b012206
1d011417163b0132360156281d441d27271d8921152307070f1316151a22ab3950282839441e
36891d28281dcd1c28fe931b0f04160e15090a27170133225038cd3a28271900000000010044
0000015602ac001f0000133534262322061d012322061514163b011114163332363511333236
35342623cd140e0e14221112131022140e0f13671012111101deab11121310ab140e0e14fe88
101211110178150d0f130000000100440000019a02ac001100002132363534262b0111342623
220615111433017810121111ef150d0f1423150d0f13024511121310fd992200000000020044
0000008902ac000d001900003711342623220615111416333236031416333236353426232206
89150d0f14150e0f1345140f0e14140e0f1422019a11111210fe6610121102780e14140e0f14
1400000000010044ffff019b02ac0021000013113426232206151114163332363d0137171633
323635342f01373635342623220789150d0f14150e0f1321b30a100e1608b2ab0f150d0c0a01
34015511121310fd9910121111bc19e90f150d0b0be9810a110d16070044004501df000002ad
000000000000ff330000b800002c4bb800095058b101018e59b801ff85b800441db900090003
5f5e2db800012c2020456944b001602db800022cb800012a212db800032c2046b00325465258
2359208a208a49648a204620686164b004254620686164525823658a592f20b00053586920b0
00545821b040591b6920b000545821b0406559593a2db800042c2046b00425465258238a5920
46206a6164b0042546206a61645258238a592ffd2db800052c4b20b0032650585158b080441b
b04044591b21212045b0c05058b0c0441b2159592db800062c2020456944b001602020457d69
1844b001602db800072cb800062a2db800082c4b20b003265358b0801bb040598a8a20b00326
5358b0022621b0c08a8a1b8a235920b0032653582321b801008a8a1b8a235920b80003265358
b0032545b8014050582321b8014023211bb003254523212321591b2159442db800092c4b5358
45441b2121592d00000100000001199941d5b0175f0f3cf5001903e800000000b5729f210000
0000b5729f21ffbcff3305570379000000030002000000000000000100000379ff33001a059b
ffbcffff055700010000000000000000000000000000000d01f4001f02f0004401de00440223
004401de004401de004401de00440223004401de0044019a004401de004400cd004401de0044
00000022005c008400c000da0104013a0162019e01cc01ea0214024600010000000d006d0007
00000000000200000000000a00000200015300000001bb00000002000200002b2bbd00010042
00330025001600082bbd0000004300340025001700082bba0002000400072b0000>
] def
/f-0-0 currentdict end definefont pop
%%EndResource
%%EndSetup
%%Page: 1 1
%%BeginPageSetup
%%PageBoundingBox: 22 0 794 261
%%EndPageSetup
q 22 0 772 261 rectclip
1 0 0 -1 0 261 cm q
1 g
538.793 0 m 786.434 0 l 790.102 0 793.051 2.949 793.051 6.617 c 793.051
254.258 l 793.051 257.922 790.102 260.875 786.434 260.875 c 538.793 260.875
l 535.129 260.875 532.18 257.922 532.18 254.258 c 532.18 6.617 l 532.18
2.949 535.129 0 538.793 0 c h
538.793 0 m f
0 0.560784 0 rg
750.832 65.785 m 750.52 66.793 l 750.203 67.801 l 749.949 68.746 l 749.699
69.691 l 749.508 70.512 l 749.32 71.332 l 749.258 71.836 l 749.133 72.277
l 749.07 72.781 l 749.07 74.672 l 749.133 75.488 l 749.195 76.371 l 749.383
77.441 l 749.574 78.578 l 749.824 79.836 l 750.078 81.285 l 750.453 82.863
l 750.895 84.625 l 751.336 86.453 l 751.902 88.469 l 752.473 90.676 l 753.102
93.008 l 753.859 95.527 l 754.613 98.301 l 755.055 99.875 l 755.559 101.578
l 756.125 103.34 l 756.629 105.23 l 757.199 107.184 l 757.828 109.203 l
758.457 111.281 l 759.086 113.488 l 759.719 115.691 l 760.41 118.023 l
761.168 120.418 l 761.859 122.875 l 762.617 125.395 l 763.371 127.98 l 764.129
130.562 l 764.887 133.148 l 765.641 135.855 l 766.398 138.504 l 767.152
141.148 l 767.91 143.797 l 768.664 146.441 l 769.422 149.09 l 770.18 151.672
l 770.871 154.191 l 771.562 156.715 l 772.195 159.109 l 772.824 161.504
l 773.453 163.832 l 774.023 166.039 l 774.59 168.246 l 775.094 170.324
l 775.598 172.34 l 776.102 174.23 l 776.543 176.121 l 776.922 177.887 l
777.297 179.586 l 777.867 182.297 l 778.309 184.754 l 778.746 187.148 l
779.062 189.355 l 779.379 191.496 l 779.566 193.449 l 779.691 195.34 l 779.82
197.168 l 779.82 198.805 l 779.758 200.32 l 779.691 201.77 l 779.566 203.027
l 779.379 204.227 l 779.125 205.359 l 778.875 206.305 l 778.621 207.188
l 778.309 208.008 l 777.93 208.699 l 777.613 209.328 l 777.234 209.961
l 776.855 210.465 l 776.543 211.031 l 775.785 211.914 l 775.094 212.859
l 774.336 213.738 l 773.582 214.559 l 772.762 215.316 l 772.004 216.07 l
771.25 216.641 l 770.555 217.145 l 769.926 217.586 l 769.422 217.836 l
768.918 217.961 l 768.539 218.023 l 768.16 217.898 l 767.91 217.586 l 767.656
217.145 l 767.469 216.512 l 767.344 215.758 l 767.215 214.938 l 767.09
213.992 l 766.902 213.047 l 766.711 212.039 l 766.461 211.094 l 766.27 210.336
l 765.957 209.645 l 765.641 208.824 l 765.262 208.008 l 764.316 206.117
l 763.75 205.109 l 763.184 204.035 l 762.555 202.965 l 761.859 201.77 l
761.168 200.633 l 760.473 199.438 l 759.719 198.176 l 758.961 196.914 l
758.457 195.969 l 757.891 195.023 l 757.262 193.953 l 756.629 192.883 l
756 191.75 l 755.242 190.488 l 754.551 189.227 l 753.793 187.906 l 753.039
186.582 l 752.219 185.133 l 751.398 183.746 l 750.582 182.297 l 749.762
180.91 l 748.941 179.461 l 748.188 178.074 l 747.367 176.688 l 746.609
175.367 l 745.793 173.98 l 745.035 172.719 l 744.281 171.395 l 743.586 170.199
l 742.895 169 l 742.199 167.805 l 741.445 166.605 l 740.688 165.348 l 739.934
164.086 l 739.176 162.762 l 738.418 161.504 l 737.602 160.18 l 736.781
158.855 l 736.023 157.531 l 735.207 156.211 l 734.449 154.949 l 733.695
153.688 l 732.938 152.492 l 732.18 151.293 l 731.488 150.16 l 730.793 149.027
l 730.164 148.02 l 729.535 147.008 l 728.906 146 l 728.273 145.055 l 727.52
143.797 l 726.699 142.535 l 725.879 141.34 l 725.125 140.078 l 724.305
138.879 l 723.547 137.684 l 722.73 136.484 l 721.973 135.352 l 721.281 134.219
l 720.523 133.211 l 719.895 132.266 l 719.262 131.32 l 718.633 130.5 l
718.129 129.742 l 717.562 129.051 l 717.121 128.359 l 716.492 127.539 l
715.859 126.781 l 715.293 126.027 l 714.664 125.332 l 714.098 124.641 l
713.531 124.008 l 712.961 123.441 l 711.449 121.93 l 710.945 121.488 l 710.504
121.109 l 710 120.605 l 709.434 120.164 l 708.805 119.66 l 708.172 119.156
l 707.48 118.652 l 706.852 118.211 l 706.156 117.77 l 705.465 117.332 l
704.832 116.953 l 703.574 116.32 l 702.941 116.07 l 702.188 115.754 l 701.43
115.504 l 700.676 115.25 l 699.918 115.062 l 699.164 114.871 l 698.469
114.684 l 697.84 114.559 l 697.207 114.496 l 696.516 114.367 l 695.758 114.242
l 694.941 114.18 l 694.184 114.18 l 693.492 114.117 l 690.465 114.117 l
689.332 113.992 l 688.703 113.926 l 688.199 113.801 l 687.695 113.613 l
687.191 113.422 l 686.75 113.172 l 686.246 112.793 l 685.676 112.414 l
685.109 111.91 l 684.605 111.469 l 684.039 110.965 l 683.535 110.461 l 683.094
109.957 l 682.59 109.516 l 682.086 109.012 l 681.078 107.879 l 680.637
107.375 l 680.195 106.809 l 679.879 106.305 l 679.566 105.863 l 679.375
105.359 l 679.188 104.855 l 679.062 104.285 l 679 103.719 l 678.934 103.152
l 678.871 102.523 l 678.871 99.562 l 678.809 98.805 l 678.809 98.047 l
678.746 97.293 l 678.621 96.535 l 678.559 95.844 l 678.43 95.211 l 678.18
93.828 l 677.988 93.133 l 677.738 92.379 l 677.484 91.621 l 677.234 90.863
l 676.98 90.109 l 676.668 89.477 l 676.414 88.848 l 676.035 88.156 l 675.66
87.523 l 675.281 86.895 l 674.84 86.203 l 674.336 85.508 l 673.832 84.879
l 673.328 84.184 l 672.887 83.617 l 671.879 82.484 l 671.5 82.043 l 671.059
81.602 l 670.617 81.098 l 669.609 80.09 l 668.98 79.523 l 668.348 78.957
l 667.656 78.324 l 666.961 77.758 l 666.27 77.191 l 665.449 76.562 l 664.695
75.93 l 664 75.426 l 663.309 74.922 l 662.551 74.418 l 661.668 73.789 l
660.789 73.156 l 659.844 72.527 l 658.77 71.773 l 657.699 71.078 l 656.504
70.324 l 655.367 69.504 l 654.172 68.746 l 652.91 67.93 l 651.715 67.172
l 650.453 66.352 l 649.191 65.535 l 647.934 64.777 l 646.988 64.148 l 646.043
63.516 l 645.035 62.887 l 643.965 62.258 l 642.828 61.562 l 641.695 60.871
l 640.559 60.113 l 639.301 59.359 l 638.039 58.602 l 636.781 57.848 l 635.457
57.027 l 634.133 56.27 l 632.809 55.453 l 631.488 54.633 l 630.227 53.875
l 628.902 53.121 l 627.641 52.301 l 626.383 51.609 l 625.184 50.852 l 623.988
50.16 l 622.789 49.465 l 621.594 48.773 l 620.27 48.016 l 619.008 47.262
l 617.625 46.441 l 616.301 45.684 l 614.914 44.867 l 613.527 44.047 l 612.078
43.227 l 610.691 42.406 l 609.242 41.59 l 607.855 40.832 l 606.406 40.012
l 605.082 39.195 l 603.762 38.438 l 602.5 37.746 l 601.238 37.051 l 600.105
36.359 l 599.035 35.727 l 597.965 35.16 l 596.074 34.027 l 594.812 33.27
l 593.551 32.578 l 592.355 31.82 l 591.223 31.129 l 590.023 30.5 l 588.953
29.867 l 587.883 29.238 l 586.875 28.734 l 585.863 28.23 l 584.984 27.789
l 584.164 27.41 l 583.344 27.094 l 582.652 26.781 l 581.895 26.59 l 580.949
26.34 l 579.941 26.152 l 578.996 25.961 l 578.051 25.836 l 577.23 25.711
l 576.477 25.582 l 575.848 25.395 l 575.406 25.141 l 575.09 24.891 l 575.027
24.512 l 575.027 24.133 l 575.152 23.629 l 575.469 23.125 l 575.848 22.496
l 576.352 21.801 l 576.98 21.047 l 577.672 20.289 l 578.492 19.473 l 579.312
18.715 l 580.195 17.957 l 581.074 17.266 l 582.02 16.574 l 582.59 16.195
l 583.094 15.816 l 583.723 15.438 l 584.352 15.125 l 585.047 14.746 l 585.863
14.43 l 586.746 14.18 l 587.691 13.926 l 588.828 13.676 l 589.961 13.484
l 591.285 13.359 l 592.734 13.297 l 594.246 13.234 l 595.883 13.234 l 597.711
13.359 l 599.602 13.484 l 601.555 13.676 l 603.699 13.988 l 605.902 14.305
l 608.297 14.746 l 610.754 15.188 l 613.465 15.754 l 615.164 16.133 l 616.93
16.508 l 618.82 16.949 l 620.711 17.453 l 622.727 17.957 l 624.809 18.461
l 627.012 19.031 l 629.219 19.598 l 631.551 20.227 l 633.945 20.855 l 636.34
21.488 l 638.859 22.18 l 641.379 22.875 l 643.965 23.629 l 646.609 24.387
l 649.258 25.141 l 651.902 25.898 l 654.551 26.656 l 657.195 27.41 l 659.906
28.168 l 662.488 28.922 l 665.074 29.68 l 667.656 30.434 l 670.176 31.191
l 672.633 31.883 l 675.027 32.641 l 677.359 33.332 l 679.566 33.965 l 681.77
34.594 l 683.852 35.223 l 685.867 35.855 l 687.82 36.422 l 689.711 36.926
l 691.477 37.492 l 693.176 37.934 l 694.75 38.438 l 697.523 39.195 l 700.043
39.949 l 702.375 40.582 l 704.582 41.148 l 706.598 41.715 l 708.426 42.156
l 710.191 42.598 l 711.766 42.91 l 713.215 43.227 l 714.473 43.48 l 715.609
43.668 l 716.68 43.793 l 717.562 43.922 l 718.383 43.984 l 719.703 43.984
l 720.273 43.922 l 720.777 43.855 l 721.219 43.793 l 721.723 43.668 l 722.539
43.543 l 723.359 43.289 l 724.305 43.102 l 725.25 42.848 l 726.258 42.535
l 728.273 41.902 l 729.281 41.527 l 730.289 41.211 l 731.234 40.895 l 732.117
40.582 l 733 40.266 l 733.82 39.949 l 734.641 39.637 l 735.52 39.258 l
736.402 38.941 l 737.285 38.629 l 738.168 38.312 l 738.988 37.996 l 739.867
37.684 l 740.625 37.43 l 741.383 37.242 l 742.074 37.051 l 742.766 36.926
l 743.523 36.801 l 744.344 36.672 l 745.16 36.609 l 746.738 36.609 l 747.492
36.672 l 748.188 36.738 l 748.816 36.863 l 749.383 36.988 l 749.887 37.176
l 750.453 37.367 l 751.023 37.617 l 751.527 37.934 l 751.969 38.25 l 752.41
38.562 l 752.785 38.941 l 753.164 39.258 l 753.48 39.57 l 753.793 39.887
l 754.109 40.266 l 754.488 40.645 l 754.805 41.086 l 755.117 41.527 l 755.434
42.031 l 755.684 42.598 l 755.938 43.164 l 756.062 43.668 l 756.188 44.234
l 756.316 44.867 l 756.379 45.559 l 756.441 46.316 l 756.441 47.891 l 756.379
48.711 l 756.254 49.527 l 756.125 50.285 l 756 50.977 l 755.812 51.672
l 755.621 52.426 l 755.371 53.184 l 755.055 54.066 l 754.738 54.883 l 754.426
55.766 l 754.109 56.648 l 753.73 57.531 l 753.418 58.414 l 753.102 59.23
l 752.785 60.051 l 752.473 60.934 l 752.156 61.816 l 751.84 62.762 l 751.465
63.77 l h
750.832 65.785 m f
0.504104 w
0 J
2 j
[] 0.0 d
4 M q 1 0 0 1 0 0 cm
750.832 65.785 m 750.52 66.793 l 750.203 67.801 l 749.949 68.746 l 749.699
69.691 l 749.508 70.512 l 749.32 71.332 l 749.258 71.836 l 749.133 72.277
l 749.07 72.781 l 749.07 74.672 l 749.133 75.488 l 749.195 76.371 l 749.383
77.441 l 749.574 78.578 l 749.824 79.836 l 750.078 81.285 l 750.453 82.863
l 750.895 84.625 l 751.336 86.453 l 751.902 88.469 l 752.473 90.676 l 753.102
93.008 l 753.859 95.527 l 754.613 98.301 l 755.055 99.875 l 755.559 101.578
l 756.125 103.34 l 756.629 105.23 l 757.199 107.184 l 757.828 109.203 l
758.457 111.281 l 759.086 113.488 l 759.719 115.691 l 760.41 118.023 l
761.168 120.418 l 761.859 122.875 l 762.617 125.395 l 763.371 127.98 l 764.129
130.562 l 764.887 133.148 l 765.641 135.855 l 766.398 138.504 l 767.152
141.148 l 767.91 143.797 l 768.664 146.441 l 769.422 149.09 l 770.18 151.672
l 770.871 154.191 l 771.562 156.715 l 772.195 159.109 l 772.824 161.504
l 773.453 163.832 l 774.023 166.039 l 774.59 168.246 l 775.094 170.324
l 775.598 172.34 l 776.102 174.23 l 776.543 176.121 l 776.922 177.887 l
777.297 179.586 l 777.867 182.297 l 778.309 184.754 l 778.746 187.148 l
779.062 189.355 l 779.379 191.496 l 779.566 193.449 l 779.691 195.34 l 779.82
197.168 l 779.82 198.805 l 779.758 200.32 l 779.691 201.77 l 779.566 203.027
l 779.379 204.227 l 779.125 205.359 l 778.875 206.305 l 778.621 207.188
l 778.309 208.008 l 777.93 208.699 l 777.613 209.328 l 777.234 209.961
l 776.855 210.465 l 776.543 211.031 l 775.785 211.914 l 775.094 212.859
l 774.336 213.738 l 773.582 214.559 l 772.762 215.316 l 772.004 216.07 l
771.25 216.641 l 770.555 217.145 l 769.926 217.586 l 769.422 217.836 l
768.918 217.961 l 768.539 218.023 l 768.16 217.898 l 767.91 217.586 l 767.656
217.145 l 767.469 216.512 l 767.344 215.758 l 767.215 214.938 l 767.09
213.992 l 766.902 213.047 l 766.711 212.039 l 766.461 211.094 l 766.27 210.336
l 765.957 209.645 l 765.641 208.824 l 765.262 208.008 l 764.316 206.117
l 763.75 205.109 l 763.184 204.035 l 762.555 202.965 l 761.859 201.77 l
761.168 200.633 l 760.473 199.438 l 759.719 198.176 l 758.961 196.914 l
758.457 195.969 l 757.891 195.023 l 757.262 193.953 l 756.629 192.883 l
756 191.75 l 755.242 190.488 l 754.551 189.227 l 753.793 187.906 l 753.039
186.582 l 752.219 185.133 l 751.398 183.746 l 750.582 182.297 l 749.762
180.91 l 748.941 179.461 l 748.188 178.074 l 747.367 176.688 l 746.609
175.367 l 745.793 173.98 l 745.035 172.719 l 744.281 171.395 l 743.586 170.199
l 742.895 169 l 742.199 167.805 l 741.445 166.605 l 740.688 165.348 l 739.934
164.086 l 739.176 162.762 l 738.418 161.504 l 737.602 160.18 l 736.781
158.855 l 736.023 157.531 l 735.207 156.211 l 734.449 154.949 l 733.695
153.688 l 732.938 152.492 l 732.18 151.293 l 731.488 150.16 l 730.793 149.027
l 730.164 148.02 l 729.535 147.008 l 728.906 146 l 728.273 145.055 l 727.52
143.797 l 726.699 142.535 l 725.879 141.34 l 725.125 140.078 l 724.305
138.879 l 723.547 137.684 l 722.73 136.484 l 721.973 135.352 l 721.281 134.219
l 720.523 133.211 l 719.895 132.266 l 719.262 131.32 l 718.633 130.5 l
718.129 129.742 l 717.562 129.051 l 717.121 128.359 l 716.492 127.539 l
715.859 126.781 l 715.293 126.027 l 714.664 125.332 l 714.098 124.641 l
713.531 124.008 l 712.961 123.441 l 711.449 121.93 l 710.945 121.488 l 710.504
121.109 l 710 120.605 l 709.434 120.164 l 708.805 119.66 l 708.172 119.156
l 707.48 118.652 l 706.852 118.211 l 706.156 117.77 l 705.465 117.332 l
704.832 116.953 l 703.574 116.32 l 702.941 116.07 l 702.188 115.754 l 701.43
115.504 l 700.676 115.25 l 699.918 115.062 l 699.164 114.871 l 698.469
114.684 l 697.84 114.559 l 697.207 114.496 l 696.516 114.367 l 695.758 114.242
l 694.941 114.18 l 694.184 114.18 l 693.492 114.117 l 690.465 114.117 l
689.332 113.992 l 688.703 113.926 l 688.199 113.801 l 687.695 113.613 l
687.191 113.422 l 686.75 113.172 l 686.246 112.793 l 685.676 112.414 l
685.109 111.91 l 684.605 111.469 l 684.039 110.965 l 683.535 110.461 l 683.094
109.957 l 682.59 109.516 l 682.086 109.012 l 681.078 107.879 l 680.637
107.375 l 680.195 106.809 l 679.879 106.305 l 679.566 105.863 l 679.375
105.359 l 679.188 104.855 l 679.062 104.285 l 679 103.719 l 678.934 103.152
l 678.871 102.523 l 678.871 99.562 l 678.809 98.805 l 678.809 98.047 l
678.746 97.293 l 678.621 96.535 l 678.559 95.844 l 678.43 95.211 l 678.18
93.828 l 677.988 93.133 l 677.738 92.379 l 677.484 91.621 l 677.234 90.863
l 676.98 90.109 l 676.668 89.477 l 676.414 88.848 l 676.035 88.156 l 675.66
87.523 l 675.281 86.895 l 674.84 86.203 l 674.336 85.508 l 673.832 84.879
l 673.328 84.184 l 672.887 83.617 l 671.879 82.484 l 671.5 82.043 l 671.059
81.602 l 670.617 81.098 l 669.609 80.09 l 668.98 79.523 l 668.348 78.957
l 667.656 78.324 l 666.961 77.758 l 666.27 77.191 l 665.449 76.562 l 664.695
75.93 l 664 75.426 l 663.309 74.922 l 662.551 74.418 l 661.668 73.789 l
660.789 73.156 l 659.844 72.527 l 658.77 71.773 l 657.699 71.078 l 656.504
70.324 l 655.367 69.504 l 654.172 68.746 l 652.91 67.93 l 651.715 67.172
l 650.453 66.352 l 649.191 65.535 l 647.934 64.777 l 646.988 64.148 l 646.043
63.516 l 645.035 62.887 l 643.965 62.258 l 642.828 61.562 l 641.695 60.871
l 640.559 60.113 l 639.301 59.359 l 638.039 58.602 l 636.781 57.848 l 635.457
57.027 l 634.133 56.27 l 632.809 55.453 l 631.488 54.633 l 630.227 53.875
l 628.902 53.121 l 627.641 52.301 l 626.383 51.609 l 625.184 50.852 l 623.988
50.16 l 622.789 49.465 l 621.594 48.773 l 620.27 48.016 l 619.008 47.262
l 617.625 46.441 l 616.301 45.684 l 614.914 44.867 l 613.527 44.047 l 612.078
43.227 l 610.691 42.406 l 609.242 41.59 l 607.855 40.832 l 606.406 40.012
l 605.082 39.195 l 603.762 38.438 l 602.5 37.746 l 601.238 37.051 l 600.105
36.359 l 599.035 35.727 l 597.965 35.16 l 596.074 34.027 l 594.812 33.27
l 593.551 32.578 l 592.355 31.82 l 591.223 31.129 l 590.023 30.5 l 588.953
29.867 l 587.883 29.238 l 586.875 28.734 l 585.863 28.23 l 584.984 27.789
l 584.164 27.41 l 583.344 27.094 l 582.652 26.781 l 581.895 26.59 l 580.949
26.34 l 579.941 26.152 l 578.996 25.961 l 578.051 25.836 l 577.23 25.711
l 576.477 25.582 l 575.848 25.395 l 575.406 25.141 l 575.09 24.891 l 575.027
24.512 l 575.027 24.133 l 575.152 23.629 l 575.469 23.125 l 575.848 22.496
l 576.352 21.801 l 576.98 21.047 l 577.672 20.289 l 578.492 19.473 l 579.312
18.715 l 580.195 17.957 l 581.074 17.266 l 582.02 16.574 l 582.59 16.195
l 583.094 15.816 l 583.723 15.438 l 584.352 15.125 l 585.047 14.746 l 585.863
14.43 l 586.746 14.18 l 587.691 13.926 l 588.828 13.676 l 589.961 13.484
l 591.285 13.359 l 592.734 13.297 l 594.246 13.234 l 595.883 13.234 l 597.711
13.359 l 599.602 13.484 l 601.555 13.676 l 603.699 13.988 l 605.902 14.305
l 608.297 14.746 l 610.754 15.188 l 613.465 15.754 l 615.164 16.133 l 616.93
16.508 l 618.82 16.949 l 620.711 17.453 l 622.727 17.957 l 624.809 18.461
l 627.012 19.031 l 629.219 19.598 l 631.551 20.227 l 633.945 20.855 l 636.34
21.488 l 638.859 22.18 l 641.379 22.875 l 643.965 23.629 l 646.609 24.387
l 649.258 25.141 l 651.902 25.898 l 654.551 26.656 l 657.195 27.41 l 659.906
28.168 l 662.488 28.922 l 665.074 29.68 l 667.656 30.434 l 670.176 31.191
l 672.633 31.883 l 675.027 32.641 l 677.359 33.332 l 679.566 33.965 l 681.77
34.594 l 683.852 35.223 l 685.867 35.855 l 687.82 36.422 l 689.711 36.926
l 691.477 37.492 l 693.176 37.934 l 694.75 38.438 l 697.523 39.195 l 700.043
39.949 l 702.375 40.582 l 704.582 41.148 l 706.598 41.715 l 708.426 42.156
l 710.191 42.598 l 711.766 42.91 l 713.215 43.227 l 714.473 43.48 l 715.609
43.668 l 716.68 43.793 l 717.562 43.922 l 718.383 43.984 l 719.703 43.984
l 720.273 43.922 l 720.777 43.855 l 721.219 43.793 l 721.723 43.668 l 722.539
43.543 l 723.359 43.289 l 724.305 43.102 l 725.25 42.848 l 726.258 42.535
l 728.273 41.902 l 729.281 41.527 l 730.289 41.211 l 731.234 40.895 l 732.117
40.582 l 733 40.266 l 733.82 39.949 l 734.641 39.637 l 735.52 39.258 l
736.402 38.941 l 737.285 38.629 l 738.168 38.312 l 738.988 37.996 l 739.867
37.684 l 740.625 37.43 l 741.383 37.242 l 742.074 37.051 l 742.766 36.926
l 743.523 36.801 l 744.344 36.672 l 745.16 36.609 l 746.738 36.609 l 747.492
36.672 l 748.188 36.738 l 748.816 36.863 l 749.383 36.988 l 749.887 37.176
l 750.453 37.367 l 751.023 37.617 l 751.527 37.934 l 751.969 38.25 l 752.41
38.562 l 752.785 38.941 l 753.164 39.258 l 753.48 39.57 l 753.793 39.887
l 754.109 40.266 l 754.488 40.645 l 754.805 41.086 l 755.117 41.527 l 755.434
42.031 l 755.684 42.598 l 755.938 43.164 l 756.062 43.668 l 756.188 44.234
l 756.316 44.867 l 756.379 45.559 l 756.441 46.316 l 756.441 47.891 l 756.379
48.711 l 756.254 49.527 l 756.125 50.285 l 756 50.977 l 755.812 51.672
l 755.621 52.426 l 755.371 53.184 l 755.055 54.066 l 754.738 54.883 l 754.426
55.766 l 754.109 56.648 l 753.73 57.531 l 753.418 58.414 l 753.102 59.23
l 752.785 60.051 l 752.473 60.934 l 752.156 61.816 l 751.84 62.762 l 751.465
63.77 l h
750.832 65.785 m S Q
17.958715 w
1 J
0 j
q 1 0 0 1 0 0 cm
583.219 238.188 m 582.852 222.684 570.367 210.199 554.863 209.832 c S Q
q 1 0 0 1 0 0 cm
625.754 238.188 m 625.836 219.363 618.395 201.281 605.082 187.969 c 591.77
174.656 573.688 167.215 554.863 167.301 c S Q
q 1 0 0 1 0 0 cm
668.285 238.188 m 668.301 208.102 656.359 179.242 635.082 157.969 c 613.809
136.695 584.949 124.75 554.863 124.766 c S Q
q 1 0 0 1 0 0 cm
710.82 238.188 m 710.68 152.113 640.938 82.371 554.863 82.23 c S Q
0 0.501961 0.501961 rg
BT
144.000001 0 0 -144.000001 12.326648 108.318331 Tm
/f-0-0 1 Tf
[(WFB-ng)]TJ
0 -1 Td
[(DataLink)]TJ
ET
Q Q
showpage
%%Trailer
end
%%EOF

BIN
doc/logo-big.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

130
doc/logo-big.svg Normal file
View File

@ -0,0 +1,130 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Creator: fig2dev Version 3.2.6a -->
<!-- CreationDate: 2022-09-07 09:58:42 -->
<!-- Magnification: 1.05 -->
<svg
width="793.05176pt"
height="260.87396pt"
viewBox="5489 719 12585.519 4139.9998"
version="1.1"
id="svg16"
sodipodi:docname="logo-big.svg"
inkscape:version="1.2.1 (9c6d41e, 2022-07-14)"
inkscape:export-filename="logo-big.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<metadata
id="metadata22">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs20" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1147"
id="namedview18"
showgrid="false"
inkscape:zoom="0.67816092"
inkscape:cx="92.161017"
inkscape:cy="168.83898"
inkscape:window-x="1366"
inkscape:window-y="31"
inkscape:window-maximized="1"
inkscape:current-layer="svg16"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="pt" />
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:2285.24px;line-height:100%;font-family:'GOST type B';-inkscape-font-specification:'GOST type B';letter-spacing:0px;word-spacing:0px;fill:#008080;fill-opacity:1;stroke:none;stroke-width:11.9023px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="5807.4766"
y="2437.9829"
id="text26"><tspan
sodipodi:role="line"
id="tspan24"
x="5807.4766"
y="2437.9829"
style="font-size:2285.24px;fill:#008080;stroke-width:11.9023px">WFB-ng</tspan><tspan
sodipodi:role="line"
x="5807.4766"
y="4723.2227"
style="font-size:2285.24px;fill:#008080;stroke-width:11.9023px"
id="tspan28">DataLink</tspan></text>
<g
fill="none"
id="g28"
transform="matrix(1.0726947,0,0,1.0726947,8125.3361,-436.134)">
<!-- Line -->
<rect
x="5490"
y="1125"
width="3735"
height="3735"
rx="105"
fill="#ffffff"
id="rect16" />
<!-- Line -->
<polygon
points="8656,2003 8655,2010 8655,2017 8655,2026 8655,2036 8656,2047 8658,2061 8660,2076 8664,2094 8668,2115 8674,2138 8680,2163 8687,2191 8696,2222 8705,2256 8716,2293 8722,2315 8729,2338 8736,2362 8743,2387 8751,2413 8759,2441 8768,2470 8777,2500 8786,2532 8796,2564 8805,2597 8815,2631 8825,2666 8835,2701 8846,2736 8856,2771 8866,2806 8876,2841 8885,2875 8894,2909 8903,2942 8912,2974 8920,3005 8928,3034 8936,3063 8942,3091 8949,3117 8955,3142 8960,3166 8965,3189 8973,3224 8979,3257 8984,3288 8988,3317 8990,3344 8992,3369 8993,3392 8993,3413 8992,3432 8990,3450 8987,3465 8984,3479 8980,3491 8976,3502 8971,3511 8967,3519 8962,3527 8957,3534 8947,3546 8938,3558 8928,3569 8917,3580 8907,3589 8897,3597 8888,3604 8880,3608 8874,3610 8869,3611 8864,3609 8860,3604 8858,3596 8856,3586 8854,3574 8852,3561 8850,3548 8846,3534 8843,3525 8840,3516 8835,3505 8830,3494 8824,3482 8817,3469 8809,3455 8801,3441 8792,3426 8783,3411 8774,3395 8764,3379 8757,3367 8750,3355 8743,3342 8735,3329 8727,3314 8718,3299 8709,3283 8699,3266 8690,3249 8680,3232 8670,3215 8660,3197 8650,3180 8640,3163 8630,3146 8621,3130 8612,3114 8602,3098 8593,3082 8584,3066 8574,3049 8564,3033 8554,3016 8543,2998 8533,2980 8522,2963 8511,2945 8501,2927 8490,2910 8480,2894 8470,2878 8461,2862 8451,2848 8443,2834 8434,2820 8426,2808 8416,2792 8406,2776 8396,2761 8386,2745 8376,2730 8367,2715 8357,2701 8348,2687 8339,2674 8331,2662 8323,2651 8316,2641 8309,2632 8303,2624 8295,2613 8287,2603 8279,2594 8271,2585 8264,2576 8256,2569 8249,2562 8243,2555 8237,2550 8231,2544 8223,2538 8215,2531 8207,2524 8197,2517 8188,2511 8179,2505 8170,2500 8162,2495 8153,2491 8143,2487 8133,2483 8123,2480 8112,2477 8102,2474 8093,2472 8085,2471 8074,2469 8063,2468 8051,2468 8041,2467 8031,2467 8023,2467 8014,2467 8006,2467 7997,2466 7989,2465 7981,2462 7974,2460 7967,2455 7960,2450 7951,2443 7943,2436 7936,2429 7929,2422 7922,2415 7914,2407 7907,2399 7900,2391 7894,2384 7890,2377 7887,2369 7885,2362 7883,2353 7882,2344 7882,2336 7882,2328 7882,2319 7882,2310 7881,2299 7881,2288 7880,2277 7878,2266 7877,2257 7875,2248 7873,2238 7870,2228 7866,2217 7863,2207 7859,2198 7855,2189 7850,2180 7845,2171 7839,2162 7833,2153 7826,2143 7819,2135 7812,2127 7806,2119 7800,2113 7795,2107 7788,2101 7781,2094 7773,2086 7765,2079 7756,2071 7746,2063 7736,2055 7726,2047 7717,2041 7708,2034 7698,2027 7687,2019 7675,2011 7662,2002 7649,1993 7634,1983 7619,1974 7604,1964 7589,1954 7573,1944 7558,1934 7542,1924 7529,1916 7516,1907 7502,1899 7487,1889 7472,1880 7456,1870 7439,1860 7422,1849 7405,1839 7387,1828 7369,1817 7351,1807 7334,1796 7317,1786 7300,1776 7284,1766 7268,1757 7252,1748 7236,1738 7220,1729 7204,1720 7187,1710 7170,1700 7153,1690 7135,1680 7118,1670 7101,1660 7084,1651 7067,1641 7051,1632 7036,1623 7021,1615 7008,1607 6995,1600 6983,1593 6971,1586 6955,1576 6939,1567 6924,1558 6909,1549 6895,1541 6881,1533 6868,1526 6856,1520 6845,1515 6834,1510 6825,1507 6816,1504 6802,1500 6789,1498 6776,1496 6764,1494 6754,1492 6746,1490 6741,1486 6739,1481 6740,1476 6742,1470 6747,1462 6753,1453 6761,1443 6771,1433 6781,1422 6793,1412 6804,1403 6817,1393 6824,1388 6831,1383 6840,1379 6849,1374 6860,1370 6872,1366 6886,1363 6901,1360 6919,1358 6938,1357 6959,1357 6982,1358 7007,1360 7034,1362 7063,1366 7094,1371 7127,1377 7163,1385 7185,1390 7209,1395 7234,1401 7260,1408 7288,1414 7317,1422 7346,1430 7377,1438 7409,1447 7442,1456 7476,1465 7510,1474 7545,1484 7580,1494 7615,1504 7650,1515 7685,1525 7720,1535 7754,1545 7787,1554 7819,1564 7850,1573 7881,1582 7910,1591 7938,1599 7964,1607 7989,1614 8013,1621 8036,1628 8058,1634 8095,1645 8129,1654 8159,1663 8187,1670 8213,1676 8236,1682 8256,1686 8274,1690 8290,1692 8303,1694 8315,1695 8325,1696 8333,1695 8340,1695 8347,1694 8354,1693 8364,1690 8376,1687 8388,1684 8401,1681 8415,1676 8428,1672 8442,1668 8455,1663 8466,1659 8478,1655 8489,1651 8500,1646 8512,1642 8523,1638 8535,1633 8546,1629 8557,1626 8567,1622 8576,1620 8585,1618 8596,1616 8607,1615 8618,1614 8629,1614 8640,1615 8649,1616 8657,1618 8664,1620 8672,1623 8680,1627 8687,1632 8693,1637 8698,1642 8703,1647 8708,1652 8713,1657 8718,1663 8723,1670 8727,1678 8730,1686 8732,1693 8734,1701 8735,1710 8736,1721 8736,1732 8735,1743 8734,1754 8732,1765 8730,1774 8728,1783 8725,1793 8721,1804 8717,1815 8713,1827 8709,1838 8704,1850 8700,1861 8696,1872 8692,1884 8687,1895 8683,1908 8678,1922 8674,1935 8670,1949 8666,1962 8663,1974 8660,1986 8658,1997 "
fill="#008f00"
stroke="#008f00"
stroke-width="8px"
stroke-linejoin="bevel"
id="polygon18" />
<!-- Arc -->
<path
d="M 6300,4500 A 461,461 0 0 0 5850,4050"
stroke="#008f00"
stroke-width="285px"
stroke-linecap="round"
id="path20" />
<!-- Arc -->
<path
d="M 6975,4500 A 1120,1120 0 0 0 5850,3375"
stroke="#008f00"
stroke-width="285px"
stroke-linecap="round"
id="path22" />
<!-- Arc -->
<path
d="M 7650,4500 A 1799,1799 0 0 0 5850,2700"
stroke="#008f00"
stroke-width="285px"
stroke-linecap="round"
id="path24" />
<!-- Arc -->
<path
d="M 8325,4500 A 2479,2479 0 0 0 5850,2025"
stroke="#008f00"
stroke-width="285px"
stroke-linecap="round"
id="path26" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.1 KiB

197
doc/logo.eps Normal file
View File

@ -0,0 +1,197 @@
%!PS-Adobe-3.0 EPSF-3.0
%%Title: logo.fig
%%Creator: fig2dev Version 3.2.6a
%%CreationDate: 2022-09-07 17:34:11
%%BoundingBox: 0 0 236 236
%Magnification: 1.0000
%%EndComments
%%BeginProlog
/$F2psDict 200 dict def
$F2psDict begin
$F2psDict /mtrx matrix put
/col-1 {0 setgray} bind def
/col7 {1.000 1.000 1.000 srgb} bind def
/col12 {0.000 0.560 0.000 srgb} bind def
end
/cp {closepath} bind def
/ef {eofill} bind def
/gr {grestore} bind def
/gs {gsave} bind def
/sa {save} bind def
/rs {restore} bind def
/l {lineto} bind def
/m {moveto} bind def
/rm {rmoveto} bind def
/n {newpath} bind def
/s {stroke} bind def
/sh {show} bind def
/slc {setlinecap} bind def
/slj {setlinejoin} bind def
/slw {setlinewidth} bind def
/srgb {setrgbcolor} bind def
/rot {rotate} bind def
/sc {scale} bind def
/sd {setdash} bind def
/ff {findfont} bind def
/sf {setfont} bind def
/scf {scalefont} bind def
/sw {stringwidth} bind def
/tr {translate} bind def
/tnt {dup dup currentrgbcolor
4 -2 roll dup 1 exch sub 3 -1 roll mul add
4 -2 roll dup 1 exch sub 3 -1 roll mul add
4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
bind def
/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
4 -2 roll mul srgb} bind def
/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
/$F2psEnd {$F2psEnteredState restore end} def
/pageheader {
save
newpath 0 236 moveto 0 0 lineto 236 0 lineto 236 236 lineto closepath clip newpath
-345.8 306.2 translate
1 -1 scale
$F2psBegin
10 setmiterlimit
0 slj 0 slc
0.06299 0.06299 sc
} bind def
/pagefooter {
$F2psEnd
restore
} bind def
%%EndProlog
pageheader
%
% Fig objects follow
%
%
% here starts figure with depth 50
% Polyline
0 slj
0 slc
0.000 slw
n 5595 1125 m 5490 1125 5490 4755 105 arcto 4 {pop} repeat
5490 4860 9120 4860 105 arcto 4 {pop} repeat
9225 4860 9225 1230 105 arcto 4 {pop} repeat
9225 1125 5595 1125 105 arcto 4 {pop} repeat
cp gs col7 1.00 shd ef gr
% Polyline
2 slj
7.500 slw
n 8696 1872 m 8692 1884 l 8687 1895 l 8683 1908 l 8678 1922 l 8674 1935 l
8670 1949 l 8666 1962 l 8663 1974 l 8660 1986 l 8658 1997 l
8656 2003 l 8655 2010 l 8655 2017 l 8655 2026 l 8655 2036 l
8656 2047 l 8658 2061 l 8660 2076 l 8664 2094 l 8668 2115 l
8674 2138 l 8680 2163 l 8687 2191 l 8696 2222 l 8705 2256 l
8716 2293 l 8722 2315 l 8729 2338 l 8736 2362 l 8743 2387 l
8751 2413 l 8759 2441 l 8768 2470 l 8777 2500 l 8786 2532 l
8796 2564 l 8805 2597 l 8815 2631 l 8825 2666 l 8835 2701 l
8846 2736 l 8856 2771 l 8866 2806 l 8876 2841 l 8885 2875 l
8894 2909 l 8903 2942 l 8912 2974 l 8920 3005 l 8928 3034 l
8936 3063 l 8942 3091 l 8949 3117 l 8955 3142 l 8960 3166 l
8965 3189 l 8973 3224 l 8979 3257 l 8984 3288 l 8988 3317 l
8990 3344 l 8992 3369 l 8993 3392 l 8993 3413 l 8992 3432 l
8990 3450 l 8987 3465 l 8984 3479 l 8980 3491 l 8976 3502 l
8971 3511 l 8967 3519 l 8962 3527 l 8957 3534 l 8947 3546 l
8938 3558 l 8928 3569 l 8917 3580 l 8907 3589 l 8897 3597 l
8888 3604 l 8880 3608 l 8874 3610 l 8869 3611 l 8864 3609 l
8860 3604 l 8858 3596 l 8856 3586 l 8854 3574 l 8852 3561 l
8850 3548 l 8846 3534 l 8843 3525 l 8840 3516 l 8835 3505 l
8830 3494 l 8824 3482 l 8817 3469 l 8809 3455 l 8801 3441 l
8792 3426 l 8783 3411 l 8774 3395 l 8764 3379 l 8757 3367 l
8750 3355 l 8743 3342 l 8735 3329 l 8727 3314 l 8718 3299 l
8709 3283 l 8699 3266 l 8690 3249 l 8680 3232 l 8670 3215 l
8660 3197 l 8650 3180 l 8640 3163 l 8630 3146 l 8621 3130 l
8612 3114 l 8602 3098 l 8593 3082 l 8584 3066 l 8574 3049 l
8564 3033 l 8554 3016 l 8543 2998 l 8533 2980 l 8522 2963 l
8511 2945 l 8501 2927 l 8490 2910 l 8480 2894 l 8470 2878 l
8461 2862 l 8451 2848 l 8443 2834 l 8434 2820 l 8426 2808 l
8416 2792 l 8406 2776 l 8396 2761 l 8386 2745 l 8376 2730 l
8367 2715 l 8357 2701 l 8348 2687 l 8339 2674 l 8331 2662 l
8323 2651 l 8316 2641 l 8309 2632 l 8303 2624 l 8295 2613 l
8287 2603 l 8279 2594 l 8271 2585 l 8264 2576 l 8256 2569 l
8249 2562 l 8243 2555 l 8237 2550 l 8231 2544 l 8223 2538 l
8215 2531 l 8207 2524 l 8197 2517 l 8188 2511 l 8179 2505 l
8170 2500 l 8162 2495 l 8153 2491 l 8143 2487 l 8133 2483 l
8123 2480 l 8112 2477 l 8102 2474 l 8093 2472 l 8085 2471 l
8074 2469 l 8063 2468 l 8051 2468 l 8041 2467 l 8031 2467 l
8023 2467 l 8014 2467 l 8006 2467 l 7997 2466 l 7989 2465 l
7981 2462 l 7974 2460 l 7967 2455 l 7960 2450 l 7951 2443 l
7943 2436 l 7936 2429 l 7929 2422 l 7922 2415 l 7914 2407 l
7907 2399 l 7900 2391 l 7894 2384 l 7890 2377 l 7887 2369 l
7885 2362 l 7883 2353 l 7882 2344 l 7882 2336 l 7882 2328 l
7882 2319 l 7882 2310 l 7881 2299 l 7881 2288 l 7880 2277 l
7878 2266 l 7877 2257 l 7875 2248 l 7873 2238 l 7870 2228 l
7866 2217 l 7863 2207 l 7859 2198 l 7855 2189 l 7850 2180 l
7845 2171 l 7839 2162 l 7833 2153 l 7826 2143 l 7819 2135 l
7812 2127 l 7806 2119 l 7800 2113 l 7795 2107 l 7788 2101 l
7781 2094 l 7773 2086 l 7765 2079 l 7756 2071 l 7746 2063 l
7736 2055 l 7726 2047 l 7717 2041 l 7708 2034 l 7698 2027 l
7687 2019 l 7675 2011 l 7662 2002 l 7649 1993 l 7634 1983 l
7619 1974 l 7604 1964 l 7589 1954 l 7573 1944 l 7558 1934 l
7542 1924 l 7529 1916 l 7516 1907 l 7502 1899 l 7487 1889 l
7472 1880 l 7456 1870 l 7439 1860 l 7422 1849 l 7405 1839 l
7387 1828 l 7369 1817 l 7351 1807 l 7334 1796 l 7317 1786 l
7300 1776 l 7284 1766 l 7268 1757 l 7252 1748 l 7236 1738 l
7220 1729 l 7204 1720 l 7187 1710 l 7170 1700 l 7153 1690 l
7135 1680 l 7118 1670 l 7101 1660 l 7084 1651 l 7067 1641 l
7051 1632 l 7036 1623 l 7021 1615 l 7008 1607 l 6995 1600 l
6983 1593 l 6971 1586 l 6955 1576 l 6939 1567 l 6924 1558 l
6909 1549 l 6895 1541 l 6881 1533 l 6868 1526 l 6856 1520 l
6845 1515 l 6834 1510 l 6825 1507 l 6816 1504 l 6802 1500 l
6789 1498 l 6776 1496 l 6764 1494 l 6754 1492 l 6746 1490 l
6741 1486 l 6739 1481 l 6740 1476 l 6742 1470 l 6747 1462 l
6753 1453 l 6761 1443 l 6771 1433 l 6781 1422 l 6793 1412 l
6804 1403 l 6817 1393 l 6824 1388 l 6831 1383 l 6840 1379 l
6849 1374 l 6860 1370 l 6872 1366 l 6886 1363 l 6901 1360 l
6919 1358 l 6938 1357 l 6959 1357 l 6982 1358 l 7007 1360 l
7034 1362 l 7063 1366 l 7094 1371 l 7127 1377 l 7163 1385 l
7185 1390 l 7209 1395 l 7234 1401 l 7260 1408 l 7288 1414 l
7317 1422 l 7346 1430 l 7377 1438 l 7409 1447 l 7442 1456 l
7476 1465 l 7510 1474 l 7545 1484 l 7580 1494 l 7615 1504 l
7650 1515 l 7685 1525 l 7720 1535 l 7754 1545 l 7787 1554 l
7819 1564 l 7850 1573 l 7881 1582 l 7910 1591 l 7938 1599 l
7964 1607 l 7989 1614 l 8013 1621 l 8036 1628 l 8058 1634 l
8095 1645 l 8129 1654 l 8159 1663 l 8187 1670 l 8213 1676 l
8236 1682 l 8256 1686 l 8274 1690 l 8290 1692 l 8303 1694 l
8315 1695 l 8325 1696 l 8333 1695 l 8340 1695 l 8347 1694 l
8354 1693 l 8364 1690 l 8376 1687 l 8388 1684 l 8401 1681 l
8415 1676 l 8428 1672 l 8442 1668 l 8455 1663 l 8466 1659 l
8478 1655 l 8489 1651 l 8500 1646 l 8512 1642 l 8523 1638 l
8535 1633 l 8546 1629 l 8557 1626 l 8567 1622 l 8576 1620 l
8585 1618 l 8596 1616 l 8607 1615 l 8618 1614 l 8629 1614 l
8640 1615 l 8649 1616 l 8657 1618 l 8664 1620 l 8672 1623 l
8680 1627 l 8687 1632 l 8693 1637 l 8698 1642 l 8703 1647 l
8708 1652 l 8713 1657 l 8718 1663 l 8723 1670 l 8727 1678 l
8730 1686 l 8732 1693 l 8734 1701 l 8735 1710 l 8736 1721 l
8736 1732 l 8735 1743 l 8734 1754 l 8732 1765 l 8730 1774 l
8728 1783 l 8725 1793 l 8721 1804 l 8717 1815 l 8713 1827 l
8709 1838 l 8704 1850 l 8700 1861 l
cp gs col12 1.00 shd ef gr gs col12 s gr
% Arc
285.000 slw
1 slc
n 5838.8 4511.2 461.4 -1.3972 -88.6028 arcn
gs col12 s gr
% Arc
n 5855.1 4494.9 1119.9 0.2614 -90.2614 arcn
gs col12 s gr
% Arc
n 5850.7 4499.3 1799.3 0.0232 -90.0232 arcn
gs col12 s gr
% Arc
n 5846.3 4503.7 2478.7 -0.0860 -89.9140 arcn
gs col12 s gr
% here ends figure;
pagefooter
showpage
%%Trailer
%EOF

30
doc/logo.fig Normal file
View File

@ -0,0 +1,30 @@
#FIG 3.2 Produced by xfig version 3.2.6a
Landscape
Center
Metric
A4
100.00
Single
-2
1200 2
5 1 0 20 12 7 48 -1 -1 0.000 1 1 0 0 5838.750 4511.250 6300 4500 6165 4185 5850 4050
5 1 0 20 12 7 48 -1 -1 0.000 1 1 0 0 5855.110 4494.890 6975 4500 6647 3703 5850 3375
5 1 0 20 12 7 48 -1 -1 0.000 1 1 0 0 5850.730 4499.270 7650 4500 7127 3231 5850 2700
5 1 0 20 12 7 48 -1 -1 0.000 1 1 0 0 5846.278 4503.722 8325 4500 7601 2753 5850 2025
6 6705 1305 9045 3645
3 1 0 1 12 12 49 -1 20 0.000 0 0 0 38
8741 1761 8696 1867 8650 2004 8650 2096 9045 3372 8962 3547
8847 3645 8863 3538 8779 3409 8605 3098 8415 2786 8293 2604
8232 2543 8164 2490 8081 2467 8020 2467 7974 2467 7929 2422
7882 2377 7882 2330 7882 2270 7860 2186 7807 2118 7746 2057
7563 1935 7252 1745 6941 1571 6812 1487 6705 1503 6804 1388
6979 1305 8255 1700 8346 1700 8483 1655 8589 1609 8673 1616
8703 1647 8734 1677
1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
1.000 1.000 1.000 1.000 1.000 1.000 1.000 1.000
1.000 1.000 1.000 1.000 1.000 1.000
-6
2 4 0 0 12 7 50 -1 20 0.000 0 0 7 0 0 5
9225 1125 5490 1125 5490 4860 9225 4860 9225 1125

83
doc/logo.svg Normal file
View File

@ -0,0 +1,83 @@
<?xml version="1.0" standalone="no"?>
<!-- Creator: fig2dev Version 3.2.6a -->
<!-- CreationDate: 2022-09-07 17:33:03 -->
<!-- Magnification: 1.05 -->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="236pt" height="236pt"
viewBox="5489 1124 3737 3737">
<g fill="none">
<!-- Line -->
<rect x="5490" y="1125" width="3735" height="3735" rx="105" fill="#ffffff"/>
<!-- Line -->
<polygon points=" 8696,1872 8692,1884 8687,1895 8683,1908 8678,1922 8674,1935 8670,1949 8666,1962
8663,1974 8660,1986 8658,1997 8656,2003 8655,2010 8655,2017 8655,2026 8655,2036
8656,2047 8658,2061 8660,2076 8664,2094 8668,2115 8674,2138 8680,2163 8687,2191
8696,2222 8705,2256 8716,2293 8722,2315 8729,2338 8736,2362 8743,2387 8751,2413
8759,2441 8768,2470 8777,2500 8786,2532 8796,2564 8805,2597 8815,2631 8825,2666
8835,2701 8846,2736 8856,2771 8866,2806 8876,2841 8885,2875 8894,2909 8903,2942
8912,2974 8920,3005 8928,3034 8936,3063 8942,3091 8949,3117 8955,3142 8960,3166
8965,3189 8973,3224 8979,3257 8984,3288 8988,3317 8990,3344 8992,3369 8993,3392
8993,3413 8992,3432 8990,3450 8987,3465 8984,3479 8980,3491 8976,3502 8971,3511
8967,3519 8962,3527 8957,3534 8947,3546 8938,3558 8928,3569 8917,3580 8907,3589
8897,3597 8888,3604 8880,3608 8874,3610 8869,3611 8864,3609 8860,3604 8858,3596
8856,3586 8854,3574 8852,3561 8850,3548 8846,3534 8843,3525 8840,3516 8835,3505
8830,3494 8824,3482 8817,3469 8809,3455 8801,3441 8792,3426 8783,3411 8774,3395
8764,3379 8757,3367 8750,3355 8743,3342 8735,3329 8727,3314 8718,3299 8709,3283
8699,3266 8690,3249 8680,3232 8670,3215 8660,3197 8650,3180 8640,3163 8630,3146
8621,3130 8612,3114 8602,3098 8593,3082 8584,3066 8574,3049 8564,3033 8554,3016
8543,2998 8533,2980 8522,2963 8511,2945 8501,2927 8490,2910 8480,2894 8470,2878
8461,2862 8451,2848 8443,2834 8434,2820 8426,2808 8416,2792 8406,2776 8396,2761
8386,2745 8376,2730 8367,2715 8357,2701 8348,2687 8339,2674 8331,2662 8323,2651
8316,2641 8309,2632 8303,2624 8295,2613 8287,2603 8279,2594 8271,2585 8264,2576
8256,2569 8249,2562 8243,2555 8237,2550 8231,2544 8223,2538 8215,2531 8207,2524
8197,2517 8188,2511 8179,2505 8170,2500 8162,2495 8153,2491 8143,2487 8133,2483
8123,2480 8112,2477 8102,2474 8093,2472 8085,2471 8074,2469 8063,2468 8051,2468
8041,2467 8031,2467 8023,2467 8014,2467 8006,2467 7997,2466 7989,2465 7981,2462
7974,2460 7967,2455 7960,2450 7951,2443 7943,2436 7936,2429 7929,2422 7922,2415
7914,2407 7907,2399 7900,2391 7894,2384 7890,2377 7887,2369 7885,2362 7883,2353
7882,2344 7882,2336 7882,2328 7882,2319 7882,2310 7881,2299 7881,2288 7880,2277
7878,2266 7877,2257 7875,2248 7873,2238 7870,2228 7866,2217 7863,2207 7859,2198
7855,2189 7850,2180 7845,2171 7839,2162 7833,2153 7826,2143 7819,2135 7812,2127
7806,2119 7800,2113 7795,2107 7788,2101 7781,2094 7773,2086 7765,2079 7756,2071
7746,2063 7736,2055 7726,2047 7717,2041 7708,2034 7698,2027 7687,2019 7675,2011
7662,2002 7649,1993 7634,1983 7619,1974 7604,1964 7589,1954 7573,1944 7558,1934
7542,1924 7529,1916 7516,1907 7502,1899 7487,1889 7472,1880 7456,1870 7439,1860
7422,1849 7405,1839 7387,1828 7369,1817 7351,1807 7334,1796 7317,1786 7300,1776
7284,1766 7268,1757 7252,1748 7236,1738 7220,1729 7204,1720 7187,1710 7170,1700
7153,1690 7135,1680 7118,1670 7101,1660 7084,1651 7067,1641 7051,1632 7036,1623
7021,1615 7008,1607 6995,1600 6983,1593 6971,1586 6955,1576 6939,1567 6924,1558
6909,1549 6895,1541 6881,1533 6868,1526 6856,1520 6845,1515 6834,1510 6825,1507
6816,1504 6802,1500 6789,1498 6776,1496 6764,1494 6754,1492 6746,1490 6741,1486
6739,1481 6740,1476 6742,1470 6747,1462 6753,1453 6761,1443 6771,1433 6781,1422
6793,1412 6804,1403 6817,1393 6824,1388 6831,1383 6840,1379 6849,1374 6860,1370
6872,1366 6886,1363 6901,1360 6919,1358 6938,1357 6959,1357 6982,1358 7007,1360
7034,1362 7063,1366 7094,1371 7127,1377 7163,1385 7185,1390 7209,1395 7234,1401
7260,1408 7288,1414 7317,1422 7346,1430 7377,1438 7409,1447 7442,1456 7476,1465
7510,1474 7545,1484 7580,1494 7615,1504 7650,1515 7685,1525 7720,1535 7754,1545
7787,1554 7819,1564 7850,1573 7881,1582 7910,1591 7938,1599 7964,1607 7989,1614
8013,1621 8036,1628 8058,1634 8095,1645 8129,1654 8159,1663 8187,1670 8213,1676
8236,1682 8256,1686 8274,1690 8290,1692 8303,1694 8315,1695 8325,1696 8333,1695
8340,1695 8347,1694 8354,1693 8364,1690 8376,1687 8388,1684 8401,1681 8415,1676
8428,1672 8442,1668 8455,1663 8466,1659 8478,1655 8489,1651 8500,1646 8512,1642
8523,1638 8535,1633 8546,1629 8557,1626 8567,1622 8576,1620 8585,1618 8596,1616
8607,1615 8618,1614 8629,1614 8640,1615 8649,1616 8657,1618 8664,1620 8672,1623
8680,1627 8687,1632 8693,1637 8698,1642 8703,1647 8708,1652 8713,1657 8718,1663
8723,1670 8727,1678 8730,1686 8732,1693 8734,1701 8735,1710 8736,1721 8736,1732
8735,1743 8734,1754 8732,1765 8730,1774 8728,1783 8725,1793 8721,1804 8717,1815
8713,1827 8709,1838 8704,1850 8700,1861" fill="#008f00"
stroke="#008f00" stroke-width="8px" stroke-linejoin="bevel"/>
<!-- Arc -->
<path d="M 6300,4500 A 461 461 0 0 0 5850 4050"
stroke="#008f00" stroke-width="285px" stroke-linecap="round"/>
<!-- Arc -->
<path d="M 6975,4500 A 1120 1120 0 0 0 5850 3375"
stroke="#008f00" stroke-width="285px" stroke-linecap="round"/>
<!-- Arc -->
<path d="M 7650,4500 A 1799 1799 0 0 0 5850 2700"
stroke="#008f00" stroke-width="285px" stroke-linecap="round"/>
<!-- Arc -->
<path d="M 8325,4500 A 2479 2479 0 0 0 5850 2025"
stroke="#008f00" stroke-width="285px" stroke-linecap="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

174
doc/wfb-ng-std-draft.md Normal file
View File

@ -0,0 +1,174 @@
% WFB-NG Data Transport Standard [Draft]
% Vasily Evseenko <<svpcom@p2ptech.org>>
% Aug 29, 2022
## Introduction
The purpose of this document is to standardize the data transfer protocol
via raw wifi radio over long distances. In this context, "long distance" is the distance over which the standard 802.11 ACK mechanism does not work.
Many areas of robotics require an inexpensive and long-range point-to-point or point-to-multipoint communication channel.
The proposed solution allows you to transmit arbitrary data streams at speeds up to 8mbps (MCS # 1 modulation) over a distance of tens of kilometers
using ordinary wifi adapters that support the transmission of "raw" packets. At the moment, these are adapters based on Realtek RTL8812AU chips.
## Areas of use:
- Communication between robots and ground station
- Communication of amateur satellites (CUBESAT) with the earth
- Digital radio communication on the ground
- ...
## Work principles
The main limitation of the transmission range of standard WiFi is the requirement to receive an ACK packet from the receiver in a strictly defined time interval after transmission.
When the distance between two stations exceeds ~200m, then the receiver does not have time to confirm the receipt of the packet and data transmission becomes impossible.
Some WiFi adapters have a so-called "raw" mode for receiving and transmitting packets.
In "raw" WiFi mode, the adapter can receive and transmit packets bypassing the standard 802.11 protocol stack. In particular, you can turn off the requirements for sending and receiving ACK packets.
In this case, the limitation on the maximum range is removed (the range now depends only on the sensitivity of the receiver and the power of the transmitter).
But requires to make own medium access control layer (MAC layer).
## Protocol description
The protocol supports point-to-point links. But each of two peers can simultaneously participate in an arbitrary number of links.
Each link has:
- Own set of encryption keys
- Up to 256 unidirectional data streams.
The last four bytes of the sender's MAC address are used to set the connection membership.
Thus the MAC address has the format: `0x57, 0x42, 0xaa, 0xbb, 0xcc, 0xdd`, where the first two bytes are the protocol header (`'W'`,`'B'`),
then three bytes - the link id and the last byte - the number of the stream inside the link.
First address byte `'W'`(0x57) has two lower bits set which means that address is multicast and locally administred.
1. The initial data transfer quantum is a UDP packet. The contents of the packet is opaque and can be any of:
- RTP packet with video or audio.
- Mavlink packet
- IP tunnel data packet.
- ...
2. Next, the packet stream is processed by the FEC codec (using [zfec](http://info.iet.unipi.it/~luigi/fec.html) -- Erasure codes based on Vandermonde matrices.)
3. FEC packets are encrypted with the aead_chacha20poly1305 stream cipher using the libsodium library
4. The result is transmitted to the air in the form of one WiFi packet.
### Stream allocation scheme:
Down streams (vehicle to GS): 0 - 127
Up streams (GS to vehicle): 128 - 255
Stream ranges:
* 0 - 15: video streams, 0 is default video stream
* 16 - 31: mavlink streams, 16 is default mavlink stream
* 32 - 47: tunnel streams, 32 is default tunnel stream
All other ranges reserved for future use
## Radio packets format
There are two packet types
1. Data packet (`packet_type = 1`, has encrypted and fec-encoded data)
2. Session packet (`packet_type = 2`, has encrypted session key)
``` .c
static uint8_t ieee80211_header[] = {
0x08, 0x01, 0x00, 0x00, // data frame, not protected, from STA to DS via an AP
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // receiver is broadcast
0x57, 0x42, 0xaa, 0xbb, 0xcc, 0xdd, // last four bytes will be replaced by channel_id
0x57, 0x42, 0xaa, 0xbb, 0xcc, 0xdd, // last four bytes will be replaced by channel_id
0x00, 0x00, // (seq_num << 4) + fragment_num
};
```
```
radiotap_header:
ieee_80211_header:
1. Data packet:
wblock_hdr_t { packet_type = 1, nonce = (block_idx << 8) + fragment_idx }
wpacket_hdr_t { flags, packet_size } #
data #
+-- encrypted and authenticated by session key
2. Session packet:
wsession_hdr_t { packet_type = 2, nonce = random() }
wsession_data_t { epoch, channel_id, session_key } # -- encrypted and signed using crypto_box_easy(rx_publickey, tx_secretkey)
data nonce: 56bit block_idx + 8bit fragment_idx
session nonce: crypto_box_NONCEBYTES of random bytes
```
``` .c
// Network packet headers. All numbers are in network (big endian) format
// Encrypted packets can be either session key or data packet.
// Session key packet
typedef struct {
uint8_t packet_type; // packet_type = 2
uint8_t session_nonce[crypto_box_NONCEBYTES]; // random data
} __attribute__ ((packed)) wsession_hdr_t;
typedef struct{
uint64_t epoch; // It allow to drop session packets from old epoch
uint32_t channel_id; // (link_id << 8) + port_number
uint8_t session_key[crypto_aead_chacha20poly1305_KEYBYTES];
} __attribute__ ((packed)) wsession_data_t;
// Data packet. Embed FEC-encoded data
typedef struct {
uint8_t packet_type; // packet_type = 1
uint64_t data_nonce; // data_nonce = (block_idx << 8) + fragment_idx
} __attribute__ ((packed)) wblock_hdr_t;
// Plain data packet after FEC decode
typedef struct {
uint8_t flags;
uint16_t packet_size;
} __attribute__ ((packed)) wpacket_hdr_t;
```
## Implementation notes
### Reference implementation
[wfb-ng.org](http://wfb-ng.org) -- reference implementation of WFB-NG protocol stack (C + Python/Twisted).
License GPLv3.
### Encryption
WFB-NG encrypts data stream using libsodium.
When TX starts, it generates new session key, encrypts it using public key authenticated encryption (cryptobox) and announce it every SESSION_KEY_ANNOUNCE_MSEC (default 1s).
Data packets encrypted by crypto_aead_chacha20poly1305_encrypt using session key and packet index as nonce.
### RX-Ring
Due to multiple RX radios with own internal queues incoming packets can arrive out of order and you need a method to rearrange them.
RX-Ring is a circular buffer, where you store packets, grouped by FEC blocks. It has two parameters: *rx_ring_front* (index of the first allocated FEC block) and
*alloc_size* -- number of allocated blocks. So rx_ring is like a queue of FEC blocks (each block can hold up to N fragments) - you append
new fragments to block(s) in the tail and fetch them from the head.
When you receive a new packet it can belongs to:
1. New fec block - you need to allocate it in RX ring (do nothing if block was already processed)
2. Already existing fec block - you need to add it to them (do nothing if packet already processed)
If you successfully decode all fragments from the block then you should yield and remove ALL unfinished blocks before it.
When you allocate a new block you have following choices:
1. Add a new block to rx ring tail.
2. Override a block at rx ring head if rx ring is full.
So you can support invariant that output UDP packets will be always ordered and no duplicates will be inside.
### Mavlink mode
By default WFB-NG encapsulates one source UDP packet to one WiFi packet. But mavlink packets are very small (usually less than 100 bytes) and
send them in separate packets produces too much overhead. You can add optimized mavlink mode.
It will pack mavlink packets into one UDP packet while size < ``MAX_PAYLOAD_SIZE`` and ``mavlink_agg_in_ms`` is not expired.

View File

@ -6,11 +6,13 @@ ReloadPropagatedFrom=wifibroadcast.service
[Service]
Type=simple
EnvironmentFile=/etc/default/wifibroadcast
# Use for multi-link setup
# Environment="WIFIBROADCAST_CFG=/etc/wifibroadcast_linkXXX.cfg"
ExecStart=/usr/bin/wfb-server %i ${WFB_NICS}
TimeoutStopSec=5s
Restart=on-failure
RestartSec=5s
StandardOutput=file:/var/log/wifibroadcast.log
# Set logging to file in wifibroadcast.cfg
StandardError=inherit
[Install]

View File

@ -80,5 +80,7 @@ setup(
author="Vasily Evseenko",
author_email="svpcom@p2ptech.org",
description="The next generation of long-range packet radio link based on raw WiFi radio",
long_description=open('README.md').read(),
long_description_content_type='text/markdown',
license="GPLv3",
)

View File

@ -1,6 +1,6 @@
/* -*- c -*-
*/
// Copyright (C) 2017, 2018 Vasily Evseenko <svpcom@p2ptech.org>
// Copyright (C) 2017 - 2022 Vasily Evseenko <svpcom@p2ptech.org>
/*
* This program is free software; you can redistribute it and/or modify
@ -20,6 +20,11 @@
#include <stdio.h>
#include <sodium.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/random.h>
int main(void)
{
@ -29,8 +34,33 @@ int main(void)
unsigned char gs_secretkey[crypto_box_SECRETKEYBYTES];
FILE *fp;
crypto_box_keypair(drone_publickey, drone_secretkey);
crypto_box_keypair(gs_publickey, gs_secretkey);
{
int fd;
int c;
if ((fd = open("/dev/random", O_RDONLY)) != -1) {
if (ioctl(fd, RNDGETENTCNT, &c) == 0 && c < 160) {
fprintf(stderr, "This system doesn't provide enough entropy to quickly generate high-quality random numbers.\n"
"Installing the rng-utils/rng-tools, jitterentropy or haveged packages may help.\n"
"On virtualized Linux environments, also consider using virtio-rng.\n"
"The service will not start until enough entropy has been collected.\n");
}
(void) close(fd);
}
}
if (sodium_init() < 0)
{
fprintf(stderr, "libsodium init failed\n");
return 1;
}
if (crypto_box_keypair(drone_publickey, drone_secretkey) !=0 ||
crypto_box_keypair(gs_publickey, gs_secretkey) != 0)
{
fprintf(stderr, "Unable to generate keys\n");
return 1;
}
if((fp = fopen("drone.key", "w")) == NULL)
{

View File

@ -1,6 +1,6 @@
// -*- C++ -*-
//
// Copyright (C) 2017 - 2020 Vasily Evseenko <svpcom@p2ptech.org>
// Copyright (C) 2017 - 2022 Vasily Evseenko <svpcom@p2ptech.org>
/*
* This program is free software; you can redistribute it and/or modify
@ -32,6 +32,8 @@
#include <netinet/in.h>
#include <arpa/inet.h>
#include <limits.h>
#include <sys/ioctl.h>
#include <linux/random.h>
extern "C"
{
@ -48,7 +50,7 @@ extern "C"
using namespace std;
Receiver::Receiver(const char *wlan, int wlan_idx, int radio_port, BaseAggregator *agg) : wlan_idx(wlan_idx), agg(agg)
Receiver::Receiver(const char *wlan, int wlan_idx, uint32_t channel_id, BaseAggregator *agg) : wlan_idx(wlan_idx), agg(agg)
{
char errbuf[PCAP_ERRBUF_SIZE];
@ -60,9 +62,7 @@ Receiver::Receiver(const char *wlan, int wlan_idx, int radio_port, BaseAggregato
if (pcap_set_snaplen(ppcap, 4096) !=0) throw runtime_error("set_snaplen failed");
if (pcap_set_promisc(ppcap, 1) != 0) throw runtime_error("set_promisc failed");
//if (pcap_set_rfmon(ppcap, 1) !=0) throw runtime_error("set_rfmon failed");
if (pcap_set_timeout(ppcap, -1) !=0) throw runtime_error("set_timeout failed");
//if (pcap_set_buffer_size(ppcap, 2048) !=0) throw runtime_error("set_buffer_size failed");
if (pcap_set_immediate_mode(ppcap, 1) != 0) throw runtime_error(string_format("pcap_set_immediate_mode failed: %s", pcap_geterr(ppcap)));
if (pcap_activate(ppcap) !=0) throw runtime_error(string_format("pcap_activate failed: %s", pcap_geterr(ppcap)));
if (pcap_setnonblock(ppcap, 1, errbuf) != 0) throw runtime_error(string_format("set_nonblock failed: %s", errbuf));
@ -71,22 +71,12 @@ Receiver::Receiver(const char *wlan, int wlan_idx, int radio_port, BaseAggregato
struct bpf_program bpfprogram;
string program;
switch (link_encap)
{
case DLT_PRISM_HEADER:
fprintf(stderr, "%s has DLT_PRISM_HEADER Encap\n", wlan);
program = string_format("radio[0x4a:4]==0x13223344 && radio[0x4e:2] == 0x55%.2x", radio_port);
break;
case DLT_IEEE802_11_RADIO:
fprintf(stderr, "%s has DLT_IEEE802_11_RADIO Encap\n", wlan);
program = string_format("ether[0x0a:4]==0x13223344 && ether[0x0e:2] == 0x55%.2x", radio_port);
break;
default:
if (link_encap != DLT_IEEE802_11_RADIO) {
throw runtime_error(string_format("unknown encapsulation on %s", wlan));
}
program = string_format("ether[0x0a:2]==0x5742 && ether[0x0c:4] == 0x%08x", channel_id);
if (pcap_compile(ppcap, &bpfprogram, program.c_str(), 1, 0) == -1) {
throw runtime_error(string_format("Unable to compile %s: %s", program.c_str(), pcap_geterr(ppcap)));
}
@ -208,9 +198,11 @@ void Receiver::loop_iter(void)
}
Aggregator::Aggregator(const string &client_addr, int client_port, int k, int n, const string &keypair) : fec_k(k), fec_n(n), seq(0), rx_ring_front(0), rx_ring_alloc(0), last_known_block((uint64_t)-1),
count_p_all(0), count_p_dec_err(0), count_p_dec_ok(0), count_p_fec_recovered(0),
count_p_lost(0), count_p_bad(0), count_p_override(0)
Aggregator::Aggregator(const string &client_addr, int client_port, int k, int n, const string &keypair, uint64_t epoch, uint32_t channel_id) : \
fec_k(k), fec_n(n), seq(0), rx_ring_front(0), rx_ring_alloc(0),
last_known_block((uint64_t)-1), epoch(epoch), channel_id(channel_id),
count_p_all(0), count_p_dec_err(0), count_p_dec_ok(0), count_p_fec_recovered(0),
count_p_lost(0), count_p_bad(0), count_p_override(0)
{
sockfd = open_udp_socket_for_tx(client_addr, client_port);
fec_p = fec_new(fec_k, fec_n);
@ -423,7 +415,7 @@ void Aggregator::log_rssi(const sockaddr_in *sockaddr, uint8_t wlan_idx, const u
void Aggregator::process_packet(const uint8_t *buf, size_t size, uint8_t wlan_idx, const uint8_t *antenna, const int8_t *rssi, sockaddr_in *sockaddr)
{
uint8_t new_session_key[sizeof(session_key)];
wsession_data_t new_session_data;
count_p_all += 1;
if(size == 0) return;
@ -447,16 +439,17 @@ void Aggregator::process_packet(const uint8_t *buf, size_t size, uint8_t wlan_id
break;
case WFB_PACKET_KEY:
if(size != sizeof(wsession_key_t))
if(size != sizeof(wsession_hdr_t) + sizeof(wsession_data_t) + crypto_box_MACBYTES)
{
fprintf(stderr, "invalid session key packet\n");
count_p_bad += 1;
return;
}
if(crypto_box_open_easy(new_session_key,
((wsession_key_t*)buf)->session_key_data, sizeof(wsession_key_t::session_key_data),
((wsession_key_t*)buf)->session_key_nonce,
if(crypto_box_open_easy((uint8_t*)&new_session_data,
buf + sizeof(wsession_hdr_t),
sizeof(wsession_data_t) + crypto_box_MACBYTES,
((wsession_hdr_t*)buf)->session_nonce,
tx_publickey, rx_secretkey) != 0)
{
fprintf(stderr, "unable to decrypt session key\n");
@ -464,12 +457,20 @@ void Aggregator::process_packet(const uint8_t *buf, size_t size, uint8_t wlan_id
return;
}
count_p_dec_ok += 1;
if (be64toh(new_session_data.epoch) < epoch || be32toh(new_session_data.channel_id) != channel_id)
{
fprintf(stderr, "session channel_id or epoch doesn't match\n");
count_p_dec_err += 1;
return;
}
if (memcmp(session_key, new_session_key, sizeof(session_key)) != 0)
count_p_dec_ok += 1;
epoch = be64toh(new_session_data.epoch);
if (memcmp(session_key, new_session_data.session_key, sizeof(session_key)) != 0)
{
fprintf(stderr, "New session detected\n");
memcpy(session_key, new_session_key, sizeof(session_key));
memcpy(session_key, new_session_data.session_key, sizeof(session_key));
rx_ring_front = 0;
rx_ring_alloc = 0;
@ -500,9 +501,9 @@ void Aggregator::process_packet(const uint8_t *buf, size_t size, uint8_t wlan_id
buf + sizeof(wblock_hdr_t), size - sizeof(wblock_hdr_t),
buf,
sizeof(wblock_hdr_t),
(uint8_t*)(&(block_hdr->nonce)), session_key) != 0)
(uint8_t*)(&(block_hdr->data_nonce)), session_key) != 0)
{
fprintf(stderr, "unable to decrypt packet #0x%" PRIx64 "\n", be64toh(block_hdr->nonce));
fprintf(stderr, "unable to decrypt packet #0x%" PRIx64 "\n", be64toh(block_hdr->data_nonce));
count_p_dec_err += 1;
return;
}
@ -512,8 +513,8 @@ void Aggregator::process_packet(const uint8_t *buf, size_t size, uint8_t wlan_id
assert(decrypted_len <= MAX_FEC_PAYLOAD);
uint64_t block_idx = be64toh(block_hdr->nonce) >> 8;
uint8_t fragment_idx = (uint8_t)(be64toh(block_hdr->nonce) & 0xff);
uint64_t block_idx = be64toh(block_hdr->data_nonce) >> 8;
uint8_t fragment_idx = (uint8_t)(be64toh(block_hdr->data_nonce) & 0xff);
// Should never happend due to generating new session key on tx side
if (block_idx > MAX_BLOCK_IDX)
@ -682,7 +683,7 @@ void Aggregator::apply_fec(int ring_idx)
fec_decode(fec_p, (const uint8_t**)in_blocks, out_blocks, index, MAX_FEC_PAYLOAD);
}
void radio_loop(int argc, char* const *argv, int optind, int radio_port, shared_ptr<BaseAggregator> agg, int log_interval)
void radio_loop(int argc, char* const *argv, int optind, uint32_t channel_id, shared_ptr<BaseAggregator> agg, int log_interval)
{
int nfds = min(argc - optind, MAX_RX_INTERFACES);
uint64_t log_send_ts = 0;
@ -693,7 +694,7 @@ void radio_loop(int argc, char* const *argv, int optind, int radio_port, shared_
for(int i = 0; i < nfds; i++)
{
rx[i] = new Receiver(argv[optind + i], i, radio_port, agg.get());
rx[i] = new Receiver(argv[optind + i], i, channel_id, agg.get());
fds[i].fd = rx[i]->getfd();
fds[i].events = POLLIN;
}
@ -817,7 +818,9 @@ void network_loop(int srv_port, Aggregator &agg, int log_interval)
int main(int argc, char* const *argv)
{
int opt;
uint8_t k = 8, n = 12, radio_port = 1;
uint8_t k = 8, n = 12, radio_port = 0;
uint32_t link_id = 0;
uint64_t epoch = 0;
int log_interval = 1000;
int client_port = 5600;
int srv_port = 0;
@ -825,7 +828,7 @@ int main(int argc, char* const *argv)
rx_mode_t rx_mode = LOCAL;
string keypair = "rx.key";
while ((opt = getopt(argc, argv, "K:fa:k:n:c:u:p:l:")) != -1) {
while ((opt = getopt(argc, argv, "K:fa:k:n:c:u:p:l:i:e:")) != -1) {
switch (opt) {
case 'K':
keypair = optarg;
@ -855,36 +858,64 @@ int main(int argc, char* const *argv)
case 'l':
log_interval = atoi(optarg);
break;
case 'i':
link_id = ((uint32_t)atoi(optarg)) & 0xffffff;
break;
case 'e':
epoch = atoll(optarg);
break;
default: /* '?' */
show_usage:
fprintf(stderr, "Local receiver: %s [-K rx_key] [-k RS_K] [-n RS_N] [-c client_addr] [-u client_port] [-p radio_port] [-l log_interval] interface1 [interface2] ...\n", argv[0]);
fprintf(stderr, "Remote (forwarder): %s -f [-c client_addr] [-u client_port] [-p radio_port] interface1 [interface2] ...\n", argv[0]);
fprintf(stderr, "Remote (aggregator): %s -a server_port [-K rx_key] [-k RS_K] [-n RS_N] [-c client_addr] [-u client_port] [-l log_interval]\n", argv[0]);
fprintf(stderr, "Default: K='%s', k=%d, n=%d, connect=%s:%d, radio_port=%d, log_interval=%d\n", keypair.c_str(), k, n, client_addr.c_str(), client_port, radio_port, log_interval);
fprintf(stderr, "Local receiver: %s [-K rx_key] [-k RS_K] [-n RS_N] [-c client_addr] [-u client_port] [-p radio_port] [-l log_interval] [-e epoch] [-i link_id] interface1 [interface2] ...\n", argv[0]);
fprintf(stderr, "Remote (forwarder): %s -f [-c client_addr] [-u client_port] [-p radio_port] [-i link_id] interface1 [interface2] ...\n", argv[0]);
fprintf(stderr, "Remote (aggregator): %s -a server_port [-K rx_key] [-k RS_K] [-n RS_N] [-c client_addr] [-u client_port] [-l log_interval] [-p radio_port] [-e epoch] [-i link_id]\n", argv[0]);
fprintf(stderr, "Default: K='%s', k=%d, n=%d, connect=%s:%d, link_id=0x%06x, radio_port=%u, epoch=%lu, log_interval=%d\n", keypair.c_str(), k, n, client_addr.c_str(), client_port, link_id, radio_port, epoch, log_interval);
fprintf(stderr, "WFB-ng version " WFB_VERSION "\n");
fprintf(stderr, "WFB-ng home page: <http://wfb-ng.org>\n");
exit(1);
}
}
{
int fd;
int c;
if ((fd = open("/dev/random", O_RDONLY)) != -1) {
if (ioctl(fd, RNDGETENTCNT, &c) == 0 && c < 160) {
fprintf(stderr, "This system doesn't provide enough entropy to quickly generate high-quality random numbers.\n"
"Installing the rng-utils/rng-tools, jitterentropy or haveged packages may help.\n"
"On virtualized Linux environments, also consider using virtio-rng.\n"
"The service will not start until enough entropy has been collected.\n");
}
(void) close(fd);
}
}
if (sodium_init() < 0)
{
fprintf(stderr, "libsodium init failed\n");
return 1;
}
try
{
uint32_t channel_id = (link_id << 8) + radio_port;
if (rx_mode == LOCAL || rx_mode == FORWARDER)
{
if (optind >= argc) goto show_usage;
shared_ptr<BaseAggregator> agg;
if(rx_mode == LOCAL){
agg = shared_ptr<Aggregator>(new Aggregator(client_addr, client_port, k, n, keypair));
agg = shared_ptr<Aggregator>(new Aggregator(client_addr, client_port, k, n, keypair, epoch, channel_id));
}else{
agg = shared_ptr<Forwarder>(new Forwarder(client_addr, client_port));
}
radio_loop(argc, argv, optind, radio_port, agg, log_interval);
radio_loop(argc, argv, optind, channel_id, agg, log_interval);
}else if(rx_mode == AGGREGATOR)
{
if (optind > argc) goto show_usage;
Aggregator agg(client_addr, client_port, k, n, keypair);
Aggregator agg(client_addr, client_port, k, n, keypair, epoch, channel_id);
network_loop(srv_port, agg, log_interval);
}else{

View File

@ -1,6 +1,6 @@
// -*- C++ -*-
//
// Copyright (C) 2017, 2018 Vasily Evseenko <svpcom@p2ptech.org>
// Copyright (C) 2017 - 2022 Vasily Evseenko <svpcom@p2ptech.org>
/*
* This program is free software; you can redistribute it and/or modify
@ -118,7 +118,7 @@ typedef std::unordered_map<uint64_t, antennaItem> antenna_stat_t;
class Aggregator : public BaseAggregator
{
public:
Aggregator(const std::string &client_addr, int client_port, int k, int n, const std::string &keypair);
Aggregator(const std::string &client_addr, int client_port, int k, int n, const std::string &keypair, uint64_t epoch, uint32_t channel_id);
~Aggregator();
virtual void process_packet(const uint8_t *buf, size_t size, uint8_t wlan_idx, const uint8_t *antenna, const int8_t *rssi, sockaddr_in *sockaddr);
virtual void dump_stats(FILE *fp);
@ -137,6 +137,8 @@ private:
int rx_ring_front; // current packet
int rx_ring_alloc; // number of allocated entries
uint64_t last_known_block; //id of last known block
uint64_t epoch; // current epoch
const uint32_t channel_id; // (link_id << 8) + port_number
// rx->tx keypair
uint8_t rx_secretkey[crypto_box_SECRETKEYBYTES];
@ -156,7 +158,7 @@ private:
class Receiver
{
public:
Receiver(const char* wlan, int wlan_idx, int port, BaseAggregator* agg);
Receiver(const char* wlan, int wlan_idx, uint32_t channel_id, BaseAggregator* agg);
~Receiver();
void loop_iter(void);
int getfd(void){ return fd; }

View File

@ -1,6 +1,6 @@
// -*- C++ -*-
//
// Copyright (C) 2017 - 2020 Vasily Evseenko <svpcom@p2ptech.org>
// Copyright (C) 2017 - 2022 Vasily Evseenko <svpcom@p2ptech.org>
/*
* This program is free software; you can redistribute it and/or modify
@ -27,6 +27,8 @@
#include <sys/resource.h>
#include <pcap/pcap.h>
#include <assert.h>
#include <sys/ioctl.h>
#include <linux/random.h>
#include <string>
#include <memory>
@ -42,9 +44,12 @@ extern "C"
using namespace std;
Transmitter::Transmitter(int k, int n, const string &keypair): fec_k(k), fec_n(n), block_idx(0),
fragment_idx(0),
max_packet_size(0)
Transmitter::Transmitter(int k, int n, const string &keypair, uint64_t epoch, uint32_t channel_id) : \
fec_k(k), fec_n(n), block_idx(0),
fragment_idx(0),
max_packet_size(0),
epoch(epoch),
channel_id(channel_id)
{
fec_p = fec_new(fec_k, fec_n);
@ -88,21 +93,35 @@ Transmitter::~Transmitter()
void Transmitter::make_session_key(void)
{
// init session key
randombytes_buf(session_key, sizeof(session_key));
session_key_packet.packet_type = WFB_PACKET_KEY;
randombytes_buf(session_key_packet.session_key_nonce, sizeof(session_key_packet.session_key_nonce));
if (crypto_box_easy(session_key_packet.session_key_data, session_key, sizeof(session_key),
session_key_packet.session_key_nonce, rx_publickey, tx_secretkey) != 0)
// fill packet header
wsession_hdr_t *session_hdr = (wsession_hdr_t *)session_key_packet;
session_hdr->packet_type = WFB_PACKET_KEY;
randombytes_buf(session_hdr->session_nonce, sizeof(session_hdr->session_nonce));
// fill packet contents
wsession_data_t session_data = { .epoch = htobe64(epoch),
.channel_id = htobe32(channel_id) };
memcpy(session_data.session_key, session_key, sizeof(session_key));
if (crypto_box_easy(session_key_packet + sizeof(wsession_hdr_t),
(uint8_t*)&session_data, sizeof(session_data),
session_hdr->session_nonce, rx_publickey, tx_secretkey) != 0)
{
throw runtime_error("Unable to make session key!");
}
}
PcapTransmitter::PcapTransmitter(int k, int n, const string &keypair, uint8_t radio_port, const vector<string> &wlans) : Transmitter(k, n, keypair),
radio_port(radio_port),
current_output(0),
ieee80211_seq(0)
PcapTransmitter::PcapTransmitter(int k, int n, const string &keypair, uint64_t epoch, uint32_t channel_id, const vector<string> &wlans) : \
Transmitter(k, n, keypair, epoch, channel_id),
channel_id(channel_id),
current_output(0),
ieee80211_seq(0)
{
char errbuf[PCAP_ERRBUF_SIZE];
for(auto it=wlans.begin(); it!=wlans.end(); it++)
@ -138,8 +157,13 @@ void PcapTransmitter::inject_packet(const uint8_t *buf, size_t size)
// ieee80211 header
memcpy(p, ieee80211_header, sizeof(ieee80211_header));
p[SRC_MAC_LASTBYTE] = radio_port;
p[DST_MAC_LASTBYTE] = radio_port;
// channel_id
uint32_t channel_id_be = htobe32(channel_id);
memcpy(p + SRC_MAC_THIRD_BYTE, &channel_id_be, sizeof(uint32_t));
memcpy(p + DST_MAC_THIRD_BYTE, &channel_id_be, sizeof(uint32_t));
// sequence number
p[FRAME_SEQ_LB] = ieee80211_seq & 0xff;
p[FRAME_SEQ_HB] = (ieee80211_seq >> 8) & 0xff;
ieee80211_seq += 16;
@ -172,13 +196,16 @@ void Transmitter::send_block_fragment(size_t packet_size)
assert(packet_size <= MAX_FEC_PAYLOAD);
block_hdr->packet_type = WFB_PACKET_DATA;
block_hdr->nonce = htobe64(((block_idx & BLOCK_IDX_MASK) << 8) + fragment_idx);
block_hdr->data_nonce = htobe64(((block_idx & BLOCK_IDX_MASK) << 8) + fragment_idx);
// encrypted payload
crypto_aead_chacha20poly1305_encrypt(ciphertext + sizeof(wblock_hdr_t), &ciphertext_len,
block[fragment_idx], packet_size,
(uint8_t*)block_hdr, sizeof(wblock_hdr_t),
NULL, (uint8_t*)(&(block_hdr->nonce)), session_key);
if (crypto_aead_chacha20poly1305_encrypt(ciphertext + sizeof(wblock_hdr_t), &ciphertext_len,
block[fragment_idx], packet_size,
(uint8_t*)block_hdr, sizeof(wblock_hdr_t),
NULL, (uint8_t*)(&(block_hdr->data_nonce)), session_key) < 0)
{
throw runtime_error("Unable to encrypt packet!");
}
inject_packet(ciphertext, sizeof(wblock_hdr_t) + ciphertext_len);
}
@ -186,7 +213,7 @@ void Transmitter::send_block_fragment(size_t packet_size)
void Transmitter::send_session_key(void)
{
//fprintf(stderr, "Announce session key\n");
inject_packet((uint8_t*)&session_key_packet, sizeof(session_key_packet));
inject_packet((uint8_t*)session_key_packet, sizeof(session_key_packet));
}
void Transmitter::send_packet(const uint8_t *buf, size_t size, uint8_t flags)
@ -303,7 +330,9 @@ void data_source(shared_ptr<Transmitter> &t, vector<int> &rx_fd, int poll_timeou
int main(int argc, char * const *argv)
{
int opt;
uint8_t k=8, n=12, radio_port=1;
uint8_t k=8, n=12, radio_port=0;
uint32_t link_id = 0x0;
uint64_t epoch = 0;
int udp_port=5600;
int bandwidth = 20;
@ -316,7 +345,7 @@ int main(int argc, char * const *argv)
string keypair = "tx.key";
while ((opt = getopt(argc, argv, "K:k:n:u:r:p:B:G:S:L:M:D:T:")) != -1) {
while ((opt = getopt(argc, argv, "K:k:n:u:r:p:B:G:S:L:M:D:T:i:e:")) != -1) {
switch (opt) {
case 'K':
keypair = optarg;
@ -354,12 +383,18 @@ int main(int argc, char * const *argv)
case 'T':
poll_timeout = atoi(optarg);
break;
case 'i':
link_id = ((uint32_t)atoi(optarg)) & 0xffffff;
break;
case 'e':
epoch = atoll(optarg);
break;
default: /* '?' */
show_usage:
fprintf(stderr, "Usage: %s [-K tx_key] [-k RS_K] [-n RS_N] [-u udp_port] [-p radio_port] [-B bandwidth] [-G guard_interval] [-S stbc] [-L ldpc] [-M mcs_index] [ -T poll_timeout ] interface1 [interface2] ...\n",
fprintf(stderr, "Usage: %s [-K tx_key] [-k RS_K] [-n RS_N] [-u udp_port] [-p radio_port] [-B bandwidth] [-G guard_interval] [-S stbc] [-L ldpc] [-M mcs_index] [-T poll_timeout] [-e epoch] [-i link_id] interface1 [interface2] ...\n",
argv[0]);
fprintf(stderr, "Default: K='%s', k=%d, n=%d, udp_port=%d, radio_port=%d bandwidth=%d guard_interval=%s stbc=%d ldpc=%d mcs_index=%d, poll_timeout=%d\n",
keypair.c_str(), k, n, udp_port, radio_port, bandwidth, short_gi ? "short" : "long", stbc, ldpc, mcs_index, poll_timeout);
fprintf(stderr, "Default: K='%s', k=%d, n=%d, udp_port=%d, link_id=0x%06x, radio_port=%u, epoch=%lu, bandwidth=%d guard_interval=%s stbc=%d ldpc=%d mcs_index=%d, poll_timeout=%d\n",
keypair.c_str(), k, n, udp_port, link_id, radio_port, epoch, bandwidth, short_gi ? "short" : "long", stbc, ldpc, mcs_index, poll_timeout);
fprintf(stderr, "Radio MTU: %lu\n", (unsigned long)MAX_PAYLOAD_SIZE);
fprintf(stderr, "WFB-ng version " WFB_VERSION "\n");
fprintf(stderr, "WFB-ng home page: <http://wfb-ng.org>\n");
@ -416,6 +451,28 @@ int main(int argc, char * const *argv)
radiotap_header[MCS_FLAGS_OFF] = flags;
radiotap_header[MCS_IDX_OFF] = mcs_index;
}
{
int fd;
int c;
if ((fd = open("/dev/random", O_RDONLY)) != -1) {
if (ioctl(fd, RNDGETENTCNT, &c) == 0 && c < 160) {
fprintf(stderr, "This system doesn't provide enough entropy to quickly generate high-quality random numbers.\n"
"Installing the rng-utils/rng-tools, jitterentropy or haveged packages may help.\n"
"On virtualized Linux environments, also consider using virtio-rng.\n"
"The service will not start until enough entropy has been collected.\n");
}
(void) close(fd);
}
}
if (sodium_init() < 0)
{
fprintf(stderr, "libsodium init failed\n");
return 1;
}
try
{
vector<int> rx_fd;
@ -430,12 +487,14 @@ int main(int argc, char * const *argv)
shared_ptr<Transmitter> t;
uint32_t channel_id = (link_id << 8) + radio_port;
if(debug_port)
{
fprintf(stderr, "Using %lu ports from %d for wlan emulation\n", wlans.size(), debug_port);
t = shared_ptr<UdpTransmitter>(new UdpTransmitter(k, n, keypair, "127.0.0.1", debug_port));
t = shared_ptr<UdpTransmitter>(new UdpTransmitter(k, n, keypair, "127.0.0.1", debug_port, epoch, channel_id));
} else {
t = shared_ptr<PcapTransmitter>(new PcapTransmitter(k, n, keypair, radio_port, wlans));
t = shared_ptr<PcapTransmitter>(new PcapTransmitter(k, n, keypair, epoch, channel_id, wlans));
}
data_source(t, rx_fd, poll_timeout);

View File

@ -1,6 +1,6 @@
// -*- C++ -*-
//
// Copyright (C) 2017, 2018 Vasily Evseenko <svpcom@p2ptech.org>
// Copyright (C) 2017 - 2022 Vasily Evseenko <svpcom@p2ptech.org>
/*
* This program is free software; you can redistribute it and/or modify
@ -32,7 +32,7 @@
class Transmitter
{
public:
Transmitter(int k, int m, const std::string &keypair);
Transmitter(int k, int m, const std::string &keypair, uint64_t epoch, uint32_t channel_id);
virtual ~Transmitter();
void send_packet(const uint8_t *buf, size_t size, uint8_t flags);
void send_session_key(void);
@ -47,28 +47,30 @@ private:
fec_t* fec_p;
int fec_k; // RS number of primary fragments in block
int fec_n; // RS total number of fragments in block
uint64_t block_idx; //block_idx << 8 + fragment_idx = nonce (64bit)
uint64_t block_idx; // (block_idx << 8) + fragment_idx = nonce (64bit)
uint8_t fragment_idx;
uint8_t** block;
size_t max_packet_size;
const uint64_t epoch; // Packets from old epoch will be discarded
const uint32_t channel_id; // (link_id << 8) + port_number
// tx->rx keypair
uint8_t tx_secretkey[crypto_box_SECRETKEYBYTES];
uint8_t rx_publickey[crypto_box_PUBLICKEYBYTES];
uint8_t session_key[crypto_aead_chacha20poly1305_KEYBYTES];
wsession_key_t session_key_packet;
uint8_t session_key_packet[sizeof(wsession_hdr_t) + sizeof(wsession_data_t) + crypto_box_MACBYTES];
};
class PcapTransmitter : public Transmitter
{
public:
PcapTransmitter(int k, int m, const std::string &keypair, uint8_t radio_port, const std::vector<std::string> &wlans);
PcapTransmitter(int k, int m, const std::string &keypair, uint64_t epoch, uint32_t channel_id, const std::vector<std::string> &wlans);
virtual ~PcapTransmitter();
virtual void select_output(int idx) { current_output = idx; }
private:
virtual void inject_packet(const uint8_t *buf, size_t size);
uint8_t radio_port;
const uint32_t channel_id;
int current_output;
uint16_t ieee80211_seq;
std::vector<pcap_t*> ppcap;
@ -78,8 +80,9 @@ private:
class UdpTransmitter : public Transmitter
{
public:
UdpTransmitter(int k, int m, const std::string &keypair, const std::string &client_addr, int base_port) : Transmitter(k, m, keypair),\
base_port(base_port)
UdpTransmitter(int k, int m, const std::string &keypair, const std::string &client_addr, int base_port, uint64_t epoch, uint32_t channel_id): \
Transmitter(k, m, keypair, epoch, channel_id), \
base_port(base_port)
{
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) throw std::runtime_error(string_format("Error opening socket: %s", strerror(errno)));

View File

@ -1,5 +1,20 @@
// -*- C++ -*-
//
// Copyright (C) 2017 - 2022 Vasily Evseenko <svpcom@p2ptech.org>
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <stdlib.h>
#include <stdarg.h>
#include <sys/socket.h>

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017, 2018, 2019 Vasily Evseenko <svpcom@p2ptech.org>
// Copyright (C) 2017 - 2022 Vasily Evseenko <svpcom@p2ptech.org>
/*
* This program is free software; you can redistribute it and/or modify
@ -67,9 +67,6 @@ extern std::string string_format(const char *format, ...);
#define MCS_KNOWN (IEEE80211_RADIOTAP_MCS_HAVE_MCS | IEEE80211_RADIOTAP_MCS_HAVE_BW | IEEE80211_RADIOTAP_MCS_HAVE_GI | IEEE80211_RADIOTAP_MCS_HAVE_STBC | IEEE80211_RADIOTAP_MCS_HAVE_FEC)
// Default is MCS#1 -- QPSK 1/2 40MHz SGI -- 30 Mbit/s
// MCS_FLAGS = (IEEE80211_RADIOTAP_MCS_BW_40 | IEEE80211_RADIOTAP_MCS_SGI | (IEEE80211_RADIOTAP_MCS_STBC_1 << IEEE80211_RADIOTAP_MCS_STBC_SHIFT))
static uint8_t radiotap_header[] __attribute__((unused)) = {
0x00, 0x00, // <-- radiotap version
0x0d, 0x00, // <- radiotap header length
@ -82,33 +79,42 @@ static uint8_t radiotap_header[] __attribute__((unused)) = {
#define MCS_FLAGS_OFF 11
#define MCS_IDX_OFF 12
//the last byte of the mac address is recycled as a port number
#define SRC_MAC_LASTBYTE 15
#define DST_MAC_LASTBYTE 21
//the last four bytes used for channel_id
#define SRC_MAC_THIRD_BYTE 12
#define DST_MAC_THIRD_BYTE 18
#define FRAME_SEQ_LB 22
#define FRAME_SEQ_HB 23
// WFB-NG MAC address format: "W:B:X:X:X:X" where XXXX is channel_id
// channel_id = (link_id << 8) + radio_port
// First address byte 'W'(0x57) has two lower bits set that means that address is multicast and locally administred
// See https://en.wikipedia.org/wiki/MAC_address for reference
static uint8_t ieee80211_header[] __attribute__((unused)) = {
0x08, 0x01, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x13, 0x22, 0x33, 0x44, 0x55, 0x66,
0x13, 0x22, 0x33, 0x44, 0x55, 0x66,
0x00, 0x00, // seq num << 4 + fragment num
0x08, 0x01, 0x00, 0x00, // data frame, not protected, from STA to DS via an AP
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // receiver is broadcast
0x57, 0x42, 0xaa, 0xbb, 0xcc, 0xdd, // last four bytes will be replaced by channel_id
0x57, 0x42, 0xaa, 0xbb, 0xcc, 0xdd, // last four bytes will be replaced by channel_id
0x00, 0x00, // (seq_num << 4) + fragment_num
};
/*
Wifibroadcast protocol:
radiotap_header
ieee_80211_header
wblock_hdr_t { packet_type, nonce = (block_idx << 8 + fragment_idx) }
wpacket_hdr_t { flags, packet_size } #
data #
+-- encrypted
WFB-NG protocol:
radiotap_header:
ieee_80211_header:
1. Data packet:
wblock_hdr_t { packet_type = 1, nonce = (block_idx << 8) + fragment_idx }
wpacket_hdr_t { flags, packet_size } #
data #
+-- encrypted and authenticated by session key
2. Session packet:
wsession_hdr_t { packet_type = 2, nonce = random() }
wsession_data_t { epoch, channel_id, session_key } # -- encrypted and signed using rx and tx keys
*/
// nonce: 56bit block_idx + 8bit fragment_idx
// data nonce: 56bit block_idx + 8bit fragment_idx
// session nonce: crypto_box_NONCEBYTES of random bytes
#define BLOCK_IDX_MASK ((1LLU << 56) - 1)
#define MAX_BLOCK_IDX ((1LLU << 55) - 1)
@ -137,15 +143,20 @@ typedef struct {
typedef struct {
uint8_t packet_type;
uint8_t session_key_nonce[crypto_box_NONCEBYTES]; // random data
uint8_t session_key_data[crypto_aead_chacha20poly1305_KEYBYTES + crypto_box_MACBYTES]; // encrypted session key
} __attribute__ ((packed)) wsession_key_t;
uint8_t session_nonce[crypto_box_NONCEBYTES]; // random data
} __attribute__ ((packed)) wsession_hdr_t;
typedef struct{
uint64_t epoch; // Drop session packets from old epoch
uint32_t channel_id; // (link_id << 8) + port_number
uint8_t session_key[crypto_aead_chacha20poly1305_KEYBYTES];
} __attribute__ ((packed)) wsession_data_t;
// Data packet. Embed FEC-encoded data
typedef struct {
uint8_t packet_type;
uint64_t nonce; // big endian, nonce = block_idx << 8 + fragment_idx
uint64_t data_nonce; // big endian, data_nonce = (block_idx << 8) + fragment_idx
} __attribute__ ((packed)) wblock_hdr_t;
// Plain data packet after FEC decode

View File

@ -1,14 +1,31 @@
### Stream allocation scheme:
## Down streams (vehicle to GS): 0 - 127
## Up streams (GS to vehicle): 128 - 255
## Stream ranges:
## 0 - 15: video streams, 0 is default video stream
## 16 - 31: mavlink streams, 16 is default mavlink stream
## 32 - 47: tunnel streams, 32 is default tunnel stream
## All other ranges reserved for future use
##
[path]
conf_dir = '/etc'
bin_dir = '/usr/bin'
tmp_dir = '/tmp'
log_dir = '/var/log'
[common]
debug = False
version = '0.0.1.trunk'
commit = None
log_file = None # Set to "wifibroadcast.log" to disable log to stdout
link_id = "default" # It will be hashed and mapped to three bytes of MAC
# You can use different link ids for multi-vehicle setup without stream remapping.
# For that case need to have several instances of wifibroadcast.cfg on GS - one for each link (GS <-> droneX)
# Redefine peer addresses, tunnel interfaces and tunnel addresses to not overlap
# Copy and rename wifibroadcast@.gs service and set path to custom wfb config.
set_nm_unmanaged = True # Set radio interface in 'unmanaged state' in NetworkManager
radio_mtu = 1445 # MAX_PAYLOAD_SIZE, don't change if doubt
mavlink_agg_timeout = 0.1 # aggragate mavlink packets if less than radio_mtu but no longer than 100ms
@ -17,13 +34,13 @@ tx_sel_delta = 3 # hysteresis for antenna selection, [dB]
wifi_channel = 165 # radio channel @5825 MHz, range: 5815-5835 MHz, width 20MHz
wifi_region = 'BO' # Set CRDA region
wifi_txpower = None # Some cards don't support tx power settings
#wifi_txpower = 58 # for 8812au
#wifi_txpower = 58 # Doesn't affect 8812au drivers, use module parameter instead
[gs_mavlink]
keypair = 'gs.key' # keypair generated by wfb-keygen
stats_port = 8001 # used by wfb-cli
stream_tx = 1 # radio port for mavlink tx
stream_rx = 2 # radio port for mavlink rx
stream_tx = 0x90 # radio port for mavlink tx
stream_rx = 0x10 # radio port for mavlink rx
fec_k = 1 # FEC K
fec_n = 2 # FEC N
fec_timeout = 0 # [ms], 0 to disable. If no new packets during timeout, emit one empty packet if FEC block is open
@ -56,7 +73,7 @@ call_on_disarm = None # call program on disarm
[gs_video]
keypair = 'gs.key' # keypair generated by wfb-keygen
stats_port = 8002 # used by wfb-cli
stream = 3 # radio port for video stream
stream = 0x0 # radio port for video stream
fec_k = 8 # FEC K
fec_n = 12 # FEC N
peer = 'connect://127.0.0.1:5600' # outgoing connection for video sink (GS)
@ -68,8 +85,8 @@ bandwidth = 20 # bandwidth 20 or 40 MHz
[drone_mavlink]
keypair = 'drone.key'
stats_port = None
stream_tx = 2
stream_rx = 1
stream_tx = 0x10
stream_rx = 0x90
port_rx = 14700
port_tx = 14701
fec_k = 1 # FEC K
@ -100,7 +117,7 @@ call_on_disarm = None # call program on disarm
[drone_video]
keypair = 'drone.key'
stats_port = None
stream = 3
stream = 0x0
fec_k = 8 # FEC K
fec_n = 12 # FEC N
fec_timeout = 0 # [ms], 0 to disable. If no new packets during timeout, emit one empty packet if FEC block is open
@ -120,8 +137,8 @@ mcs_index = 1 # mcs index
[gs_tunnel]
keypair = 'gs.key' # keypair generated by wfb-keygen
stats_port = 8003 # used by wfb-cli
stream_tx = 4 # radio port for tunnel tx
stream_rx = 5 # radio port for tunnel rx
stream_tx = 0x20 # radio port for tunnel tx
stream_rx = 0xa0 # radio port for tunnel rx
port_rx = 14800 # udp port for internal use
port_tx = 14801 # udp port range (from port_tx to port_tx + number of wlans) for internal use
fec_k = 1 # FEC K
@ -144,8 +161,8 @@ mcs_index = 1 # mcs index
[drone_tunnel]
keypair = 'drone.key'
stats_port = None
stream_tx = 5
stream_rx = 4
stream_tx = 0xa0
stream_rx = 0x20
port_rx = 14900
port_tx = 14901
fec_k = 1 # FEC K

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2018, 2019 Vasily Evseenko <svpcom@p2ptech.org>
# Copyright (C) 2018 - 2022 Vasily Evseenko <svpcom@p2ptech.org>
#
# This program is free software; you can redistribute it and/or modify

View File

@ -1,6 +1,23 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2018-2022 Vasily Evseenko <svpcom@p2ptech.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
import sys
import time
import struct
@ -88,7 +105,7 @@ class PacketSink(DatagramProtocol):
@defer.inlineCallbacks
def run_test(port_in, port_out, size, count, rate):
key = int(os.urandom(2).encode('hex'), 16)
key = int.from_bytes(os.urandom(2), 'big')
log.msg('Session: %d' % (key,))
p1 = PacketSource(('127.0.0.1', port_in), size, count, rate, key)
p2 = PacketSink(key)

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (C) 2018, 2019 Vasily Evseenko <svpcom@p2ptech.org>
# Copyright (C) 2018 - 2022 Vasily Evseenko <svpcom@p2ptech.org>
#
# This program is free software; you can redistribute it and/or modify

View File

@ -23,9 +23,11 @@ import time
import json
import os
import re
import hashlib
from itertools import groupby
from twisted.python import log, failure
from twisted.python.logfile import LogFile
from twisted.internet import reactor, defer, main as ti_main
from twisted.internet.protocol import ProcessProtocol, DatagramProtocol, Protocol, Factory
from twisted.protocols.basic import LineReceiver
@ -287,26 +289,27 @@ def init_wlans(profile, wlans):
def init(profile, wlans):
def _init_services(_):
return defer.gatherResults([defer.maybeDeferred(init_mavlink, profile, wlans),
defer.maybeDeferred(init_video, profile, wlans),
defer.maybeDeferred(init_tunnel, profile, wlans)])\
link_id = int.from_bytes(hashlib.sha1(settings.common.link_id.encode('utf-8')).digest()[:3], 'big')
return defer.gatherResults([defer.maybeDeferred(init_mavlink, profile, wlans, link_id),
defer.maybeDeferred(init_video, profile, wlans, link_id),
defer.maybeDeferred(init_tunnel, profile, wlans, link_id)])\
.addErrback(lambda f: f.trap(defer.FirstError) and f.value.subFailure)
return defer.maybeDeferred(init_wlans, profile, wlans).addCallback(_init_services)
def init_mavlink(profile, wlans):
def init_mavlink(profile, wlans, link_id):
cfg = getattr(settings, '%s_mavlink' % (profile,))
cmd_rx = ('%s -p %d -u %d -K %s -k %d -n %d' % \
cmd_rx = ('%s -p %d -u %d -K %s -k %d -n %d -i %d' % \
(os.path.join(settings.path.bin_dir, 'wfb_rx'), cfg.stream_rx,
cfg.port_rx, os.path.join(settings.path.conf_dir, cfg.keypair), cfg.fec_k, cfg.fec_n)).split() + wlans
cfg.port_rx, os.path.join(settings.path.conf_dir, cfg.keypair), cfg.fec_k, cfg.fec_n, link_id)).split() + wlans
cmd_tx = ('%s -p %d -u %d -K %s -B %d -G %s -S %d -L %d -M %d -k %d -n %d -T %d' % \
cmd_tx = ('%s -p %d -u %d -K %s -B %d -G %s -S %d -L %d -M %d -k %d -n %d -T %d -i %d' % \
(os.path.join(settings.path.bin_dir, 'wfb_tx'),
cfg.stream_tx, cfg.port_tx, os.path.join(settings.path.conf_dir, cfg.keypair),
cfg.bandwidth, "short" if cfg.short_gi else "long", cfg.stbc, cfg.ldpc, cfg.mcs_index,
cfg.fec_k, cfg.fec_n, cfg.fec_timeout)).split() + wlans
cfg.fec_k, cfg.fec_n, cfg.fec_timeout, link_id)).split() + wlans
listen = None
connect = None
@ -397,7 +400,7 @@ def init_mavlink(profile, wlans):
return defer.gatherResults(dl, consumeErrors=True).addBoth(_cleanup)\
.addErrback(lambda f: f.trap(defer.FirstError) and f.value.subFailure)
def init_video(profile, wlans):
def init_video(profile, wlans, link_id):
cfg = getattr(settings, '%s_video' % (profile,))
if listen_re.match(cfg.peer):
@ -406,11 +409,11 @@ def init_video(profile, wlans):
log.msg('Listen for video stream %d on %s:%d' % (cfg.stream, listen[0], listen[1]))
# We don't use TX diversity for video streaming due to only one transmitter on the vehichle
cmd = ('%s -p %d -u %d -K %s -B %d -G %s -S %d -L %d -M %d -k %d -n %d -T %d %s' % \
cmd = ('%s -p %d -u %d -K %s -B %d -G %s -S %d -L %d -M %d -k %d -n %d -T %d -i %d %s' % \
(os.path.join(settings.path.bin_dir, 'wfb_tx'), cfg.stream,
listen[1], os.path.join(settings.path.conf_dir, cfg.keypair),
cfg.bandwidth, "short" if cfg.short_gi else "long", cfg.stbc, cfg.ldpc, cfg.mcs_index,
cfg.fec_k, cfg.fec_n, cfg.fec_timeout, wlans[0])).split()
cfg.fec_k, cfg.fec_n, cfg.fec_timeout, link_id, wlans[0])).split()
df = TXProtocol(cmd, 'video tx').start()
elif connect_re.match(cfg.peer):
@ -422,11 +425,11 @@ def init_video(profile, wlans):
if cfg.stats_port:
reactor.listenTCP(cfg.stats_port, ant_f)
cmd = ('%s -p %d -c %s -u %d -K %s -k %d -n %d' % \
cmd = ('%s -p %d -c %s -u %d -K %s -k %d -n %d -i %d' % \
(os.path.join(settings.path.bin_dir, 'wfb_rx'),
cfg.stream, connect[0], connect[1],
os.path.join(settings.path.conf_dir, cfg.keypair),
cfg.fec_k, cfg.fec_n)).split() + wlans
cfg.fec_k, cfg.fec_n, link_id)).split() + wlans
df = RXProtocol(ant_f, cmd, 'video rx').start()
else:
@ -435,18 +438,18 @@ def init_video(profile, wlans):
log.msg('Video: %s' % (' '.join(cmd),))
return df
def init_tunnel(profile, wlans):
def init_tunnel(profile, wlans, link_id):
cfg = getattr(settings, '%s_tunnel' % (profile,))
cmd_rx = ('%s -p %d -u %d -K %s -k %d -n %d' % \
cmd_rx = ('%s -p %d -u %d -K %s -k %d -n %d -i %d' % \
(os.path.join(settings.path.bin_dir, 'wfb_rx'), cfg.stream_rx,
cfg.port_rx, os.path.join(settings.path.conf_dir, cfg.keypair), cfg.fec_k, cfg.fec_n)).split() + wlans
cfg.port_rx, os.path.join(settings.path.conf_dir, cfg.keypair), cfg.fec_k, cfg.fec_n, link_id)).split() + wlans
cmd_tx = ('%s -p %d -u %d -K %s -B %d -G %s -S %d -L %d -M %d -k %d -n %d -T %d' % \
cmd_tx = ('%s -p %d -u %d -K %s -B %d -G %s -S %d -L %d -M %d -k %d -n %d -T %d -i %d' % \
(os.path.join(settings.path.bin_dir, 'wfb_tx'),
cfg.stream_tx, cfg.port_tx, os.path.join(settings.path.conf_dir, cfg.keypair),
cfg.bandwidth, "short" if cfg.short_gi else "long", cfg.stbc, cfg.ldpc, cfg.mcs_index,
cfg.fec_k, cfg.fec_n, cfg.fec_timeout)).split() + wlans
cfg.fec_k, cfg.fec_n, cfg.fec_timeout, link_id)).split() + wlans
p_in = TUNTAPProtocol()
p_tx_l = [UDPProxyProtocol(('127.0.0.1', cfg.port_tx + i)) for i, _ in enumerate(wlans)]
@ -478,7 +481,13 @@ def init_tunnel(profile, wlans):
.addErrback(lambda f: f.trap(defer.FirstError) and f.value.subFailure)
def main():
log.startLogging(sys.stdout)
if settings.common.log_file:
log.startLogging(LogFile(settings.common.log_file,
settings.path.log_dir,
rotateLength=1024*1024,
maxRotatedFiles=10))
else:
log.startLogging(sys.stdout)
log.msg('WFB version %s-%s' % (settings.common.version, settings.common.commit[:8]))
profile, wlans = sys.argv[1], list(wlan for arg in sys.argv[2:] for wlan in arg.split())

View File

@ -37,8 +37,12 @@ class TXRXTestCase(unittest.TestCase):
self.rx_ep = reactor.listenUDP(10002, self.rxp)
self.tx_ep = reactor.listenUDP(10004, self.txp)
cmd_rx = [os.path.join(bindir, 'wfb_rx'), '-K', 'drone.key', '-a', '10001', '-u', '10002', 'wlan0']
cmd_tx = [os.path.join(bindir, 'wfb_tx'), '-K', 'gs.key', '-u', '10003', '-D', '10004', '-T', '30', 'wlan0']
link_id = int.from_bytes(os.urandom(3), 'big')
epoch = int(time.time())
cmd_rx = [os.path.join(bindir, 'wfb_rx'), '-K', 'drone.key', '-a', '10001', '-u', '10002',
'-i', str(link_id), '-e', str(epoch), 'wlan0']
cmd_tx = [os.path.join(bindir, 'wfb_tx'), '-K', 'gs.key', '-u', '10003', '-D', '10004', '-T', '30',
'-i', str(link_id), '-e', str(epoch), 'wlan0']
self.rx_pp = RXProtocol(None, cmd_rx, 'debug rx')
self.tx_pp = TXProtocol(cmd_tx, 'debug tx')