├── .hgignore ├── LICENSE ├── Makefile ├── fec.c ├── fec.h ├── ieee80211_radiotap.h ├── lib.c ├── lib.h ├── patches └── AR9271 │ ├── firmware │ ├── LICENCE.TXT │ ├── change_baserate_to_mcs3_26mbits.patch │ ├── htc_9271.fw │ ├── htc_9271.fw.24mbitofdm │ ├── htc_9271.fw.mcs1 │ ├── htc_9271.fw.mcs3 │ └── readme.txt │ └── kernel │ ├── fixed_channel_power_of_ath9k_to_20dbm.patch │ └── readme.txt ├── radiotap.c ├── radiotap.h ├── rx.c ├── rx_status_test.c ├── tx.c └── wifibroadcast.h /.hgignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | 3 | rx 4 | tx 5 | *.orig 6 | *.swp 7 | 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | wifibroadcast and its FEC code are free software 2 | 3 | you can redistribute wifibroadcast core functionality and/or 4 | it them under the terms of the GNU General Public License as 5 | published by the Free Software Foundation; either version 2 of 6 | the License. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program; see the file COPYING. 15 | If not, write to the Free Software Foundation, Inc., 16 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 | 18 | the FEC code is covered by the following license: 19 | fec.c -- forward error correction based on Vandermonde matrices 20 | 980624 21 | (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it) 22 | (C) 2001 Alain Knaff (alain@knaff.lu) 23 | 24 | Portions derived from code by Phil Karn (karn@ka9q.ampr.org), 25 | Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari 26 | Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995 27 | 28 | Redistribution and use in source and binary forms, with or without 29 | modification, are permitted provided that the following conditions 30 | are met: 31 | 32 | 1. Redistributions of source code must retain the above copyright 33 | notice, this list of conditions and the following disclaimer. 34 | 2. Redistributions in binary form must reproduce the above 35 | copyright notice, this list of conditions and the following 36 | disclaimer in the documentation and/or other materials 37 | provided with the distribution. 38 | 39 | THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND 40 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 41 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 42 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS 43 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 44 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 45 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 46 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 47 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 48 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 49 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 50 | OF SUCH DAMAGE. 51 | 52 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | LDFLAGS=-lrt -lpcap 3 | CPPFLAGS=-Wall 4 | 5 | all: rx tx rx_status_test 6 | 7 | 8 | 9 | %.o: %.c 10 | gcc -c -o $@ $< $(CPPFLAGS) 11 | 12 | 13 | rx: rx.o lib.o radiotap.o fec.o 14 | gcc -o $@ $^ $(LDFLAGS) 15 | 16 | 17 | tx: tx.o lib.o fec.o 18 | gcc -o $@ $^ $(LDFLAGS) 19 | 20 | 21 | rx_status_test: rx_status_test.o 22 | gcc -o $@ $^ $(LDFLAGS) 23 | 24 | clean: 25 | rm -f rx tx *~ *.o 26 | 27 | -------------------------------------------------------------------------------- /fec.c: -------------------------------------------------------------------------------- 1 | /*#define PROFILE*/ 2 | /* 3 | * fec.c -- forward error correction based on Vandermonde matrices 4 | * 980624 5 | * (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it) 6 | * (C) 2001 Alain Knaff (alain@knaff.lu) 7 | * 8 | * Portions derived from code by Phil Karn (karn@ka9q.ampr.org), 9 | * Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari 10 | * Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995 11 | * 12 | * Redistribution and use in source and binary forms, with or without 13 | * modification, are permitted provided that the following conditions 14 | * are met: 15 | * 16 | * 1. Redistributions of source code must retain the above copyright 17 | * notice, this list of conditions and the following disclaimer. 18 | * 2. Redistributions in binary form must reproduce the above 19 | * copyright notice, this list of conditions and the following 20 | * disclaimer in the documentation and/or other materials 21 | * provided with the distribution. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND 24 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 25 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 26 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS 27 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 28 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 29 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 30 | * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 32 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 33 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 34 | * OF SUCH DAMAGE. 35 | */ 36 | 37 | 38 | /* 39 | * The following parameter defines how many bits are used for 40 | * field elements. The code supports any value from 2 to 16 41 | * but fastest operation is achieved with 8 bit elements 42 | * This is the only parameter you may want to change. 43 | */ 44 | #define GF_BITS 8 /* code over GF(2**GF_BITS) - change to suit */ 45 | 46 | #include 47 | #include 48 | #include 49 | 50 | #include 51 | #include "fec.h" 52 | 53 | /* 54 | * stuff used for testing purposes only 55 | */ 56 | 57 | #ifdef TEST 58 | #define DEB(x) 59 | #define DDB(x) x 60 | #define DEBUG 0 /* minimal debugging */ 61 | 62 | #include 63 | #define DIFF_T(a,b) \ 64 | (1+ 1000000*(a.tv_sec - b.tv_sec) + (a.tv_usec - b.tv_usec) ) 65 | 66 | #define TICK(t) \ 67 | {struct timeval x ; \ 68 | gettimeofday(&x, NULL) ; \ 69 | t = x.tv_usec + 1000000* (x.tv_sec & 0xff ) ; \ 70 | } 71 | #define TOCK(t) \ 72 | { u_long t1 ; TICK(t1) ; \ 73 | if (t1 < t) t = 256000000 + t1 - t ; \ 74 | else t = t1 - t ; \ 75 | if (t == 0) t = 1 ;} 76 | 77 | u_long ticks[10]; /* vars for timekeeping */ 78 | #else 79 | #define DEB(x) 80 | #define DDB(x) 81 | #define TICK(x) 82 | #define TOCK(x) 83 | #endif /* TEST */ 84 | 85 | /* 86 | * You should not need to change anything beyond this point. 87 | * The first part of the file implements linear algebra in GF. 88 | * 89 | * gf is the type used to store an element of the Galois Field. 90 | * Must constain at least GF_BITS bits. 91 | * 92 | * Note: unsigned char will work up to GF(256) but int seems to run 93 | * faster on the Pentium. We use int whenever have to deal with an 94 | * index, since they are generally faster. 95 | */ 96 | /* 97 | * AK: Udpcast only uses GF_BITS=8. Remove other possibilities 98 | */ 99 | #if (GF_BITS != 8) 100 | #error "GF_BITS must be 8" 101 | #endif 102 | typedef unsigned char gf; 103 | 104 | #define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */ 105 | 106 | /* 107 | * Primitive polynomials - see Lin & Costello, Appendix A, 108 | * and Lee & Messerschmitt, p. 453. 109 | */ 110 | static char *allPp[] = { /* GF_BITS polynomial */ 111 | NULL, /* 0 no code */ 112 | NULL, /* 1 no code */ 113 | "111", /* 2 1+x+x^2 */ 114 | "1101", /* 3 1+x+x^3 */ 115 | "11001", /* 4 1+x+x^4 */ 116 | "101001", /* 5 1+x^2+x^5 */ 117 | "1100001", /* 6 1+x+x^6 */ 118 | "10010001", /* 7 1 + x^3 + x^7 */ 119 | "101110001", /* 8 1+x^2+x^3+x^4+x^8 */ 120 | "1000100001", /* 9 1+x^4+x^9 */ 121 | "10010000001", /* 10 1+x^3+x^10 */ 122 | "101000000001", /* 11 1+x^2+x^11 */ 123 | "1100101000001", /* 12 1+x+x^4+x^6+x^12 */ 124 | "11011000000001", /* 13 1+x+x^3+x^4+x^13 */ 125 | "110000100010001", /* 14 1+x+x^6+x^10+x^14 */ 126 | "1100000000000001", /* 15 1+x+x^15 */ 127 | "11010000000010001" /* 16 1+x+x^3+x^12+x^16 */ 128 | }; 129 | 130 | 131 | /* 132 | * To speed up computations, we have tables for logarithm, exponent 133 | * and inverse of a number. If GF_BITS <= 8, we use a table for 134 | * multiplication as well (it takes 64K, no big deal even on a PDA, 135 | * especially because it can be pre-initialized an put into a ROM!), 136 | * otherwhise we use a table of logarithms. 137 | * In any case the macro gf_mul(x,y) takes care of multiplications. 138 | */ 139 | 140 | static gf gf_exp[2*GF_SIZE]; /* index->poly form conversion table */ 141 | static int gf_log[GF_SIZE + 1]; /* Poly->index form conversion table */ 142 | static gf inverse[GF_SIZE+1]; /* inverse of field elem. */ 143 | /* inv[\alpha**i]=\alpha**(GF_SIZE-i-1) */ 144 | 145 | /* 146 | * modnn(x) computes x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1, 147 | * without a slow divide. 148 | */ 149 | static inline gf 150 | modnn(int x) 151 | { 152 | while (x >= GF_SIZE) { 153 | x -= GF_SIZE; 154 | x = (x >> GF_BITS) + (x & GF_SIZE); 155 | } 156 | return x; 157 | } 158 | 159 | #define SWAP(a,b,t) {t tmp; tmp=a; a=b; b=tmp;} 160 | 161 | /* 162 | * gf_mul(x,y) multiplies two numbers. If GF_BITS<=8, it is much 163 | * faster to use a multiplication table. 164 | * 165 | * USE_GF_MULC, GF_MULC0(c) and GF_ADDMULC(x) can be used when multiplying 166 | * many numbers by the same constant. In this case the first 167 | * call sets the constant, and others perform the multiplications. 168 | * A value related to the multiplication is held in a local variable 169 | * declared with USE_GF_MULC . See usage in addmul1(). 170 | */ 171 | static gf gf_mul_table[(GF_SIZE + 1)*(GF_SIZE + 1)] 172 | #ifdef WINDOWS 173 | __attribute__((aligned (16))) 174 | #else 175 | __attribute__((aligned (256))) 176 | #endif 177 | ; 178 | 179 | #define gf_mul(x,y) gf_mul_table[(x<<8)+y] 180 | 181 | #define USE_GF_MULC register gf * __gf_mulc_ 182 | #define GF_MULC0(c) __gf_mulc_ = &gf_mul_table[(c)<<8] 183 | #define GF_ADDMULC(dst, x) dst ^= __gf_mulc_[x] 184 | #define GF_MULC(dst, x) dst = __gf_mulc_[x] 185 | 186 | static void 187 | init_mul_table(void) 188 | { 189 | int i, j; 190 | for (i=0; i< GF_SIZE+1; i++) 191 | for (j=0; j< GF_SIZE+1; j++) 192 | gf_mul_table[(i<<8)+j] = gf_exp[modnn(gf_log[i] + gf_log[j]) ] ; 193 | 194 | for (j=0; j< GF_SIZE+1; j++) 195 | gf_mul_table[j] = gf_mul_table[j<<8] = 0; 196 | } 197 | 198 | /* 199 | * Generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m] 200 | * Lookup tables: 201 | * index->polynomial form gf_exp[] contains j= \alpha^i; 202 | * polynomial form -> index form gf_log[ j = \alpha^i ] = i 203 | * \alpha=x is the primitive element of GF(2^m) 204 | * 205 | * For efficiency, gf_exp[] has size 2*GF_SIZE, so that a simple 206 | * multiplication of two numbers can be resolved without calling modnn 207 | */ 208 | 209 | 210 | 211 | /* 212 | * initialize the data structures used for computations in GF. 213 | */ 214 | static void 215 | generate_gf(void) 216 | { 217 | int i; 218 | gf mask; 219 | char *Pp = allPp[GF_BITS] ; 220 | 221 | mask = 1; /* x ** 0 = 1 */ 222 | gf_exp[GF_BITS] = 0; /* will be updated at the end of the 1st loop */ 223 | /* 224 | * first, generate the (polynomial representation of) powers of \alpha, 225 | * which are stored in gf_exp[i] = \alpha ** i . 226 | * At the same time build gf_log[gf_exp[i]] = i . 227 | * The first GF_BITS powers are simply bits shifted to the left. 228 | */ 229 | for (i = 0; i < GF_BITS; i++, mask <<= 1 ) { 230 | gf_exp[i] = mask; 231 | gf_log[gf_exp[i]] = i; 232 | /* 233 | * If Pp[i] == 1 then \alpha ** i occurs in poly-repr 234 | * gf_exp[GF_BITS] = \alpha ** GF_BITS 235 | */ 236 | if ( Pp[i] == '1' ) 237 | gf_exp[GF_BITS] ^= mask; 238 | } 239 | /* 240 | * now gf_exp[GF_BITS] = \alpha ** GF_BITS is complete, so can als 241 | * compute its inverse. 242 | */ 243 | gf_log[gf_exp[GF_BITS]] = GF_BITS; 244 | /* 245 | * Poly-repr of \alpha ** (i+1) is given by poly-repr of 246 | * \alpha ** i shifted left one-bit and accounting for any 247 | * \alpha ** GF_BITS term that may occur when poly-repr of 248 | * \alpha ** i is shifted. 249 | */ 250 | mask = 1 << (GF_BITS - 1 ) ; 251 | for (i = GF_BITS + 1; i < GF_SIZE; i++) { 252 | if (gf_exp[i - 1] >= mask) 253 | gf_exp[i] = gf_exp[GF_BITS] ^ ((gf_exp[i - 1] ^ mask) << 1); 254 | else 255 | gf_exp[i] = gf_exp[i - 1] << 1; 256 | gf_log[gf_exp[i]] = i; 257 | } 258 | /* 259 | * log(0) is not defined, so use a special value 260 | */ 261 | gf_log[0] = GF_SIZE ; 262 | /* set the extended gf_exp values for fast multiply */ 263 | for (i = 0 ; i < GF_SIZE ; i++) 264 | gf_exp[i + GF_SIZE] = gf_exp[i] ; 265 | 266 | /* 267 | * again special cases. 0 has no inverse. This used to 268 | * be initialized to GF_SIZE, but it should make no difference 269 | * since noone is supposed to read from here. 270 | */ 271 | inverse[0] = 0 ; 272 | inverse[1] = 1; 273 | for (i=2; i<=GF_SIZE; i++) 274 | inverse[i] = gf_exp[GF_SIZE-gf_log[i]]; 275 | } 276 | 277 | /* 278 | * Various linear algebra operations that i use often. 279 | */ 280 | 281 | /* 282 | * addmul() computes dst[] = dst[] + c * src[] 283 | * This is used often, so better optimize it! Currently the loop is 284 | * unrolled 16 times, a good value for 486 and pentium-class machines. 285 | * The case c=0 is also optimized, whereas c=1 is not. These 286 | * calls are unfrequent in my typical apps so I did not bother. 287 | * 288 | * Note that gcc on 289 | */ 290 | #if 0 291 | #define addmul(dst, src, c, sz) \ 292 | if (c != 0) addmul1(dst, src, c, sz) 293 | #endif 294 | 295 | 296 | 297 | #define UNROLL 16 /* 1, 4, 8, 16 */ 298 | static void 299 | slow_addmul1(gf *dst1, gf *src1, gf c, int sz) 300 | { 301 | USE_GF_MULC ; 302 | register gf *dst = dst1, *src = src1 ; 303 | gf *lim = &dst[sz - UNROLL + 1] ; 304 | 305 | GF_MULC0(c) ; 306 | 307 | #if (UNROLL > 1) /* unrolling by 8/16 is quite effective on the pentium */ 308 | for (; dst < lim ; dst += UNROLL, src += UNROLL ) { 309 | GF_ADDMULC( dst[0] , src[0] ); 310 | GF_ADDMULC( dst[1] , src[1] ); 311 | GF_ADDMULC( dst[2] , src[2] ); 312 | GF_ADDMULC( dst[3] , src[3] ); 313 | #if (UNROLL > 4) 314 | GF_ADDMULC( dst[4] , src[4] ); 315 | GF_ADDMULC( dst[5] , src[5] ); 316 | GF_ADDMULC( dst[6] , src[6] ); 317 | GF_ADDMULC( dst[7] , src[7] ); 318 | #endif 319 | #if (UNROLL > 8) 320 | GF_ADDMULC( dst[8] , src[8] ); 321 | GF_ADDMULC( dst[9] , src[9] ); 322 | GF_ADDMULC( dst[10] , src[10] ); 323 | GF_ADDMULC( dst[11] , src[11] ); 324 | GF_ADDMULC( dst[12] , src[12] ); 325 | GF_ADDMULC( dst[13] , src[13] ); 326 | GF_ADDMULC( dst[14] , src[14] ); 327 | GF_ADDMULC( dst[15] , src[15] ); 328 | #endif 329 | } 330 | #endif 331 | lim += UNROLL - 1 ; 332 | for (; dst < lim; dst++, src++ ) /* final components */ 333 | GF_ADDMULC( *dst , *src ); 334 | } 335 | 336 | #if defined i386 && defined USE_ASSEMBLER 337 | 338 | #define LOOPSIZE 8 339 | 340 | static void 341 | addmul1(gf *dst1, gf *src1, gf c, int sz) 342 | { 343 | USE_GF_MULC ; 344 | 345 | GF_MULC0(c) ; 346 | 347 | if(((unsigned long)dst1 % LOOPSIZE) || 348 | ((unsigned long)src1 % LOOPSIZE) || 349 | (sz % LOOPSIZE)) { 350 | slow_addmul1(dst1, src1, c, sz); 351 | return; 352 | } 353 | 354 | asm volatile("xorl %%eax,%%eax;\n" 355 | " xorl %%edx,%%edx;\n" 356 | ".align 32;\n" 357 | "1:" 358 | " addl $8, %%edi;\n" 359 | 360 | " movb (%%esi), %%al;\n" 361 | " movb 4(%%esi), %%dl;\n" 362 | " movb (%%ebx,%%eax), %%al;\n" 363 | " movb (%%ebx,%%edx), %%dl;\n" 364 | " xorb %%al, (%%edi);\n" 365 | " xorb %%dl, 4(%%edi);\n" 366 | 367 | " movb 1(%%esi), %%al;\n" 368 | " movb 5(%%esi), %%dl;\n" 369 | " movb (%%ebx,%%eax), %%al;\n" 370 | " movb (%%ebx,%%edx), %%dl;\n" 371 | " xorb %%al, 1(%%edi);\n" 372 | " xorb %%dl, 5(%%edi);\n" 373 | 374 | " movb 2(%%esi), %%al;\n" 375 | " movb 6(%%esi), %%dl;\n" 376 | " movb (%%ebx,%%eax), %%al;\n" 377 | " movb (%%ebx,%%edx), %%dl;\n" 378 | " xorb %%al, 2(%%edi);\n" 379 | " xorb %%dl, 6(%%edi);\n" 380 | 381 | " movb 3(%%esi), %%al;\n" 382 | " movb 7(%%esi), %%dl;\n" 383 | " addl $8, %%esi;\n" 384 | " movb (%%ebx,%%eax), %%al;\n" 385 | " movb (%%ebx,%%edx), %%dl;\n" 386 | " xorb %%al, 3(%%edi);\n" 387 | " xorb %%dl, 7(%%edi);\n" 388 | 389 | " cmpl %%ecx, %%esi;\n" 390 | " jb 1b;" 391 | : : 392 | 393 | "b" (__gf_mulc_), 394 | "D" (dst1-8), 395 | "S" (src1), 396 | "c" (sz+src1) : 397 | "memory", "eax", "edx" 398 | ); 399 | } 400 | #else 401 | # define addmul1 slow_addmul1 402 | #endif 403 | 404 | static void addmul(gf *dst, gf *src, gf c, int sz) { 405 | // fprintf(stderr, "Dst=%p Src=%p, gf=%02x sz=%d\n", dst, src, c, sz); 406 | if (c != 0) addmul1(dst, src, c, sz); 407 | } 408 | 409 | /* 410 | * mul() computes dst[] = c * src[] 411 | * This is used often, so better optimize it! Currently the loop is 412 | * unrolled 16 times, a good value for 486 and pentium-class machines. 413 | * The case c=0 is also optimized, whereas c=1 is not. These 414 | * calls are unfrequent in my typical apps so I did not bother. 415 | * 416 | * Note that gcc on 417 | */ 418 | #if 0 419 | #define mul(dst, src, c, sz) \ 420 | do { if (c != 0) mul1(dst, src, c, sz); else memset(dst, 0, sz); } while(0) 421 | #endif 422 | 423 | #define UNROLL 16 /* 1, 4, 8, 16 */ 424 | static void 425 | slow_mul1(gf *dst1, gf *src1, gf c, int sz) 426 | { 427 | USE_GF_MULC ; 428 | register gf *dst = dst1, *src = src1 ; 429 | gf *lim = &dst[sz - UNROLL + 1] ; 430 | 431 | GF_MULC0(c) ; 432 | 433 | #if (UNROLL > 1) /* unrolling by 8/16 is quite effective on the pentium */ 434 | for (; dst < lim ; dst += UNROLL, src += UNROLL ) { 435 | GF_MULC( dst[0] , src[0] ); 436 | GF_MULC( dst[1] , src[1] ); 437 | GF_MULC( dst[2] , src[2] ); 438 | GF_MULC( dst[3] , src[3] ); 439 | #if (UNROLL > 4) 440 | GF_MULC( dst[4] , src[4] ); 441 | GF_MULC( dst[5] , src[5] ); 442 | GF_MULC( dst[6] , src[6] ); 443 | GF_MULC( dst[7] , src[7] ); 444 | #endif 445 | #if (UNROLL > 8) 446 | GF_MULC( dst[8] , src[8] ); 447 | GF_MULC( dst[9] , src[9] ); 448 | GF_MULC( dst[10] , src[10] ); 449 | GF_MULC( dst[11] , src[11] ); 450 | GF_MULC( dst[12] , src[12] ); 451 | GF_MULC( dst[13] , src[13] ); 452 | GF_MULC( dst[14] , src[14] ); 453 | GF_MULC( dst[15] , src[15] ); 454 | #endif 455 | } 456 | #endif 457 | lim += UNROLL - 1 ; 458 | for (; dst < lim; dst++, src++ ) /* final components */ 459 | GF_MULC( *dst , *src ); 460 | } 461 | 462 | #if defined i386 && defined USE_ASSEMBLER 463 | static void 464 | mul1(gf *dst1, gf *src1, gf c, int sz) 465 | { 466 | USE_GF_MULC ; 467 | 468 | GF_MULC0(c) ; 469 | 470 | if(((unsigned long)dst1 % LOOPSIZE) || 471 | ((unsigned long)src1 % LOOPSIZE) || 472 | (sz % LOOPSIZE)) { 473 | slow_mul1(dst1, src1, c, sz); 474 | return; 475 | } 476 | 477 | asm volatile("pushl %%eax;\n" 478 | "pushl %%edx;\n" 479 | "xorl %%eax,%%eax;\n" 480 | " xorl %%edx,%%edx;\n" 481 | "1:" 482 | " addl $8, %%edi;\n" 483 | 484 | " movb (%%esi), %%al;\n" 485 | " movb 4(%%esi), %%dl;\n" 486 | " movb (%%ebx,%%eax), %%al;\n" 487 | " movb (%%ebx,%%edx), %%dl;\n" 488 | " movb %%al, (%%edi);\n" 489 | " movb %%dl, 4(%%edi);\n" 490 | 491 | " movb 1(%%esi), %%al;\n" 492 | " movb 5(%%esi), %%dl;\n" 493 | " movb (%%ebx,%%eax), %%al;\n" 494 | " movb (%%ebx,%%edx), %%dl;\n" 495 | " movb %%al, 1(%%edi);\n" 496 | " movb %%dl, 5(%%edi);\n" 497 | 498 | " movb 2(%%esi), %%al;\n" 499 | " movb 6(%%esi), %%dl;\n" 500 | " movb (%%ebx,%%eax), %%al;\n" 501 | " movb (%%ebx,%%edx), %%dl;\n" 502 | " movb %%al, 2(%%edi);\n" 503 | " movb %%dl, 6(%%edi);\n" 504 | 505 | " movb 3(%%esi), %%al;\n" 506 | " movb 7(%%esi), %%dl;\n" 507 | " addl $8, %%esi;\n" 508 | " movb (%%ebx,%%eax), %%al;\n" 509 | " movb (%%ebx,%%edx), %%dl;\n" 510 | " movb %%al, 3(%%edi);\n" 511 | " movb %%dl, 7(%%edi);\n" 512 | 513 | " cmpl %%ecx, %%esi;\n" 514 | " jb 1b;\n" 515 | " popl %%edx;\n" 516 | " popl %%eax;" 517 | : : 518 | 519 | "b" (__gf_mulc_), 520 | "D" (dst1-8), 521 | "S" (src1), 522 | "c" (sz+src1) : 523 | "memory", "eax", "edx" 524 | ); 525 | } 526 | #else 527 | # define mul1 slow_mul1 528 | #endif 529 | 530 | static inline void mul(gf *dst, gf *src, gf c, int sz) { 531 | /*fprintf(stderr, "%p = %02x * %p\n", dst, c, src);*/ 532 | if (c != 0) mul1(dst, src, c, sz); else memset(dst, 0, sz); 533 | } 534 | 535 | /* 536 | * invert_mat() takes a matrix and produces its inverse 537 | * k is the size of the matrix. 538 | * (Gauss-Jordan, adapted from Numerical Recipes in C) 539 | * Return non-zero if singular. 540 | */ 541 | DEB( int pivloops=0; int pivswaps=0 ; /* diagnostic */) 542 | static int 543 | invert_mat(gf *src, int k) 544 | { 545 | gf c, *p ; 546 | int irow, icol, row, col, i, ix ; 547 | 548 | int error = 1 ; 549 | int indxc[k]; 550 | int indxr[k]; 551 | int ipiv[k]; 552 | gf id_row[k]; 553 | 554 | memset(id_row, 0, k*sizeof(gf)); 555 | DEB( pivloops=0; pivswaps=0 ; /* diagnostic */ ) 556 | /* 557 | * ipiv marks elements already used as pivots. 558 | */ 559 | for (i = 0; i < k ; i++) 560 | ipiv[i] = 0 ; 561 | 562 | for (col = 0; col < k ; col++) { 563 | gf *pivot_row ; 564 | /* 565 | * Zeroing column 'col', look for a non-zero element. 566 | * First try on the diagonal, if it fails, look elsewhere. 567 | */ 568 | irow = icol = -1 ; 569 | if (ipiv[col] != 1 && src[col*k + col] != 0) { 570 | irow = col ; 571 | icol = col ; 572 | goto found_piv ; 573 | } 574 | for (row = 0 ; row < k ; row++) { 575 | if (ipiv[row] != 1) { 576 | for (ix = 0 ; ix < k ; ix++) { 577 | DEB( pivloops++ ; ) 578 | if (ipiv[ix] == 0) { 579 | if (src[row*k + ix] != 0) { 580 | irow = row ; 581 | icol = ix ; 582 | goto found_piv ; 583 | } 584 | } else if (ipiv[ix] > 1) { 585 | fprintf(stderr, "singular matrix\n"); 586 | goto fail ; 587 | } 588 | } 589 | } 590 | } 591 | if (icol == -1) { 592 | fprintf(stderr, "XXX pivot not found!\n"); 593 | goto fail ; 594 | } 595 | found_piv: 596 | ++(ipiv[icol]) ; 597 | /* 598 | * swap rows irow and icol, so afterwards the diagonal 599 | * element will be correct. Rarely done, not worth 600 | * optimizing. 601 | */ 602 | if (irow != icol) { 603 | for (ix = 0 ; ix < k ; ix++ ) { 604 | SWAP( src[irow*k + ix], src[icol*k + ix], gf) ; 605 | } 606 | } 607 | indxr[col] = irow ; 608 | indxc[col] = icol ; 609 | pivot_row = &src[icol*k] ; 610 | c = pivot_row[icol] ; 611 | if (c == 0) { 612 | fprintf(stderr, "singular matrix 2\n"); 613 | goto fail ; 614 | } 615 | if (c != 1 ) { /* otherwhise this is a NOP */ 616 | /* 617 | * this is done often , but optimizing is not so 618 | * fruitful, at least in the obvious ways (unrolling) 619 | */ 620 | DEB( pivswaps++ ; ) 621 | c = inverse[ c ] ; 622 | pivot_row[icol] = 1 ; 623 | for (ix = 0 ; ix < k ; ix++ ) 624 | pivot_row[ix] = gf_mul(c, pivot_row[ix] ); 625 | } 626 | /* 627 | * from all rows, remove multiples of the selected row 628 | * to zero the relevant entry (in fact, the entry is not zero 629 | * because we know it must be zero). 630 | * (Here, if we know that the pivot_row is the identity, 631 | * we can optimize the addmul). 632 | */ 633 | id_row[icol] = 1; 634 | if (memcmp(pivot_row, id_row, k*sizeof(gf)) != 0) { 635 | for (p = src, ix = 0 ; ix < k ; ix++, p += k ) { 636 | if (ix != icol) { 637 | c = p[icol] ; 638 | p[icol] = 0 ; 639 | addmul(p, pivot_row, c, k ); 640 | } 641 | } 642 | } 643 | id_row[icol] = 0; 644 | } /* done all columns */ 645 | for (col = k-1 ; col >= 0 ; col-- ) { 646 | if (indxr[col] <0 || indxr[col] >= k) 647 | fprintf(stderr, "AARGH, indxr[col] %d\n", indxr[col]); 648 | else if (indxc[col] <0 || indxc[col] >= k) 649 | fprintf(stderr, "AARGH, indxc[col] %d\n", indxc[col]); 650 | else 651 | if (indxr[col] != indxc[col] ) { 652 | for (row = 0 ; row < k ; row++ ) { 653 | SWAP( src[row*k + indxr[col]], src[row*k + indxc[col]], gf) ; 654 | } 655 | } 656 | } 657 | error = 0 ; 658 | fail: 659 | return error ; 660 | } 661 | 662 | 663 | static int fec_initialized = 0 ; 664 | 665 | void fec_init(void) 666 | { 667 | TICK(ticks[0]); 668 | generate_gf(); 669 | TOCK(ticks[0]); 670 | DDB(fprintf(stderr, "generate_gf took %ldus\n", ticks[0]);) 671 | TICK(ticks[0]); 672 | init_mul_table(); 673 | TOCK(ticks[0]); 674 | DDB(fprintf(stderr, "init_mul_table took %ldus\n", ticks[0]);) 675 | fec_initialized = 1 ; 676 | } 677 | 678 | 679 | /** 680 | * Simplified re-implementation of Fec-Bourbon 681 | * 682 | * Following changes have been made: 683 | * 1. Avoid unnecessary copying of block data. 684 | * 2. Avoid expliciting matrixes, if we are only going to use one row 685 | * anyways 686 | * 3. Pick coefficients of Vandermonde matrix in such a way as to get 687 | * a "nicer" systematic matrix, such as for instance the following: 688 | * 1 0 0 0 0 0 0 0 689 | * 0 1 0 0 0 0 0 0 690 | * 0 0 1 0 0 0 0 0 691 | * 0 0 0 1 0 0 0 0 692 | * 0 0 0 0 1 0 0 0 693 | * 0 0 0 0 0 1 0 0 694 | * 0 0 0 0 0 0 1 0 695 | * 0 0 0 0 0 0 0 1 696 | * a b c d e f g h 697 | * b a d c f e h g 698 | * c d a b g h e f 699 | * d c b a h g f e 700 | * 701 | * This makes it easyer on processor cache, because we keep on reusing the 702 | * same small part of the multiplication table. 703 | * The trick to obtain this is to use k=128 and n=256. Use x=col for 704 | * top matrix (rather than exp(col-1) as the original did). This makes 705 | * the "inverting" polynom to be the following (coefficients of col 706 | * col of inverse of top Vandermonde matrix) 707 | * 708 | * _____ 709 | * | | 710 | * P = K | | (x - i) 711 | * col col | | 712 | * 0 < i < 128 && 713 | * i != col 714 | * 715 | * K_col must be chosen such that P_col(col) = 1, thus 716 | * 717 | * 1 718 | * --------------- 719 | * K = _____ 720 | * col | | 721 | * | | (col - i) 722 | * | | 723 | * 0 < i < 128 && 724 | * i != col 725 | * 726 | * For obvious reasons, all (col-i)'s are different foreach i (because 727 | * col constant). Moreoveover, none has the high bit set (because both 728 | * col and i have high bit unset and +/- is really a xor). Moreover 729 | * 0 is not among them (because i != col). This means that we calculate 730 | * the product of all values for 1 to 0x7f, and we have eliminated 731 | * dependancy on col. K_col can be written just k. 732 | * 733 | * Which make P_col resolves to: 734 | * _____ 735 | * | | 736 | * P = K | | (x - i) 737 | * col | | 738 | * 0 < i < 128 739 | * ------------------- 740 | * (x-col) 741 | * 742 | * When evaluating this for any x > 0x80, the following thing happens 743 | * to the numerator: all (x-i) are different for i, and have high bit 744 | * set. Thus, the set of top factors are all values from 0x80 to 0xff, 745 | * and the numerator becomes independant from x (as long as x & 0x80 = 0) 746 | * Thus, P_col(x) = L / (x-col) 747 | * In the systematic matrix value on [row,col] is P_col(row) = L/(row-col) 748 | * To simplify we multiply each bottom row by 1/L (which is a simple 749 | * scaling operation, and should not affect invertibility of any partial 750 | * matrix contained therein), and we get S[row,col] = 1/(row-col) 751 | * Benefits of all this: 752 | * - no complicated encoding matrix to compute (it's just the inverse 753 | * table!) 754 | * - cache efficiency when multiplying blocks, because we get to 755 | * reuse the same coefficients. Probability of mult table already in 756 | * cache increases. 757 | * Downside: 758 | * - less flexibility: we can for instance not do 240/200, because 759 | * 200 is more than 128, and using this technique we unfortunately 760 | * limited number of data blocks to 128 instead of 256 as would be 761 | * possible otherwise 762 | */ 763 | 764 | 765 | 766 | /* We do the matrix multiplication columns by column, instead of the 767 | * usual row-by-row, in order to capitalize on the cache freshness of 768 | * each data block . The data block only needs to be fetched once, and 769 | * can be used to be addmull'ed into all FEC blocks at once. No need 770 | * to worry about evicting FEC blocks from the cache: those are so 771 | * few (typically, 4 or 8) that they will fit easily in the cache (even 772 | * in the L2 cache...) 773 | */ 774 | void fec_encode(unsigned int blockSize, 775 | unsigned char **data_blocks, 776 | unsigned int nrDataBlocks, 777 | unsigned char **fec_blocks, 778 | unsigned int nrFecBlocks) 779 | 780 | { 781 | unsigned int blockNo; /* loop for block counter */ 782 | unsigned int row, col; 783 | 784 | assert(fec_initialized); 785 | assert(nrDataBlocks <= 128); 786 | assert(nrFecBlocks <= 128); 787 | 788 | if(!nrDataBlocks) 789 | return; 790 | 791 | for(row=0; row < nrFecBlocks; row++) 792 | mul(fec_blocks[row], data_blocks[0], inverse[128 ^ row], blockSize); 793 | 794 | for(col=129, blockNo=1; blockNo < nrDataBlocks; col++, blockNo ++) { 795 | for(row=0; row < nrFecBlocks; row++) 796 | addmul(fec_blocks[row], data_blocks[blockNo], 797 | inverse[row ^ col], 798 | blockSize); 799 | } 800 | } 801 | 802 | /** 803 | * Reduce the system by substracting all received data blocks from FEC blocks 804 | * This will allow to resolve the system by inverting a much smaller matrix 805 | * (with size being number of blocks lost, rather than number of data blocks 806 | * + fec) 807 | */ 808 | static inline void reduce(unsigned int blockSize, 809 | unsigned char **data_blocks, 810 | unsigned int nr_data_blocks, 811 | unsigned char **fec_blocks, 812 | unsigned int *fec_block_nos, 813 | unsigned int *erased_blocks, 814 | unsigned short nr_fec_blocks) 815 | { 816 | int erasedIdx=0; 817 | unsigned int col; 818 | 819 | /* First we reduce the code vector by substracting all known elements 820 | * (non-erased data packets) */ 821 | for(col=0; col 41 | #include 42 | 43 | /* Radiotap header version (from official NetBSD feed) */ 44 | #define IEEE80211RADIOTAP_VERSION "1.5" 45 | /* Base version of the radiotap packet header data */ 46 | #define PKTHDR_RADIOTAP_VERSION 0 47 | 48 | /* A generic radio capture format is desirable. There is one for 49 | * Linux, but it is neither rigidly defined (there were not even 50 | * units given for some fields) nor easily extensible. 51 | * 52 | * I suggest the following extensible radio capture format. It is 53 | * based on a bitmap indicating which fields are present. 54 | * 55 | * I am trying to describe precisely what the application programmer 56 | * should expect in the following, and for that reason I tell the 57 | * units and origin of each measurement (where it applies), or else I 58 | * use sufficiently weaselly language ("is a monotonically nondecreasing 59 | * function of...") that I cannot set false expectations for lawyerly 60 | * readers. 61 | */ 62 | 63 | /* XXX tcpdump/libpcap do not tolerate variable-length headers, 64 | * yet, so we pad every radiotap header to 64 bytes. Ugh. 65 | */ 66 | #define IEEE80211_RADIOTAP_HDRLEN 64 67 | 68 | /* The radio capture header precedes the 802.11 header. 69 | * All data in the header is little endian on all platforms. 70 | */ 71 | struct ieee80211_radiotap_header { 72 | u8 it_version; /* Version 0. Only increases 73 | * for drastic changes, 74 | * introduction of compatible 75 | * new fields does not count. 76 | */ 77 | u8 it_pad; 78 | __le16 it_len; /* length of the whole 79 | * header in bytes, including 80 | * it_version, it_pad, 81 | * it_len, and data fields. 82 | */ 83 | __le32 it_present; /* A bitmap telling which 84 | * fields are present. Set bit 31 85 | * (0x80000000) to extend the 86 | * bitmap by another 32 bits. 87 | * Additional extensions are made 88 | * by setting bit 31. 89 | */ 90 | }; 91 | 92 | #define IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK 0x80000000 93 | 94 | /* Name Data type Units 95 | * ---- --------- ----- 96 | * 97 | * IEEE80211_RADIOTAP_TSFT __le64 microseconds 98 | * 99 | * Value in microseconds of the MAC's 64-bit 802.11 Time 100 | * Synchronization Function timer when the first bit of the 101 | * MPDU arrived at the MAC. For received frames, only. 102 | * 103 | * IEEE80211_RADIOTAP_CHANNEL 2 x __le16 MHz, bitmap 104 | * 105 | * Tx/Rx frequency in MHz, followed by flags (see below). 106 | * 107 | * IEEE80211_RADIOTAP_FHSS __le16 see below 108 | * 109 | * For frequency-hopping radios, the hop set (first byte) 110 | * and pattern (second byte). 111 | * 112 | * IEEE80211_RADIOTAP_RATE u8 500kb/s 113 | * 114 | * Tx/Rx data rate 115 | * 116 | * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from 117 | * one milliwatt (dBm) 118 | * 119 | * RF signal power at the antenna, decibel difference from 120 | * one milliwatt. 121 | * 122 | * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from 123 | * one milliwatt (dBm) 124 | * 125 | * RF noise power at the antenna, decibel difference from one 126 | * milliwatt. 127 | * 128 | * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB) 129 | * 130 | * RF signal power at the antenna, decibel difference from an 131 | * arbitrary, fixed reference. 132 | * 133 | * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB) 134 | * 135 | * RF noise power at the antenna, decibel difference from an 136 | * arbitrary, fixed reference point. 137 | * 138 | * IEEE80211_RADIOTAP_LOCK_QUALITY __le16 unitless 139 | * 140 | * Quality of Barker code lock. Unitless. Monotonically 141 | * nondecreasing with "better" lock strength. Called "Signal 142 | * Quality" in datasheets. (Is there a standard way to measure 143 | * this?) 144 | * 145 | * IEEE80211_RADIOTAP_TX_ATTENUATION __le16 unitless 146 | * 147 | * Transmit power expressed as unitless distance from max 148 | * power set at factory calibration. 0 is max power. 149 | * Monotonically nondecreasing with lower power levels. 150 | * 151 | * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16 decibels (dB) 152 | * 153 | * Transmit power expressed as decibel distance from max power 154 | * set at factory calibration. 0 is max power. Monotonically 155 | * nondecreasing with lower power levels. 156 | * 157 | * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from 158 | * one milliwatt (dBm) 159 | * 160 | * Transmit power expressed as dBm (decibels from a 1 milliwatt 161 | * reference). This is the absolute power level measured at 162 | * the antenna port. 163 | * 164 | * IEEE80211_RADIOTAP_FLAGS u8 bitmap 165 | * 166 | * Properties of transmitted and received frames. See flags 167 | * defined below. 168 | * 169 | * IEEE80211_RADIOTAP_ANTENNA u8 antenna index 170 | * 171 | * Unitless indication of the Rx/Tx antenna for this packet. 172 | * The first antenna is antenna 0. 173 | * 174 | * IEEE80211_RADIOTAP_RX_FLAGS __le16 bitmap 175 | * 176 | * Properties of received frames. See flags defined below. 177 | * 178 | * IEEE80211_RADIOTAP_TX_FLAGS __le16 bitmap 179 | * 180 | * Properties of transmitted frames. See flags defined below. 181 | * 182 | * IEEE80211_RADIOTAP_RTS_RETRIES u8 data 183 | * 184 | * Number of rts retries a transmitted frame used. 185 | * 186 | * IEEE80211_RADIOTAP_DATA_RETRIES u8 data 187 | * 188 | * Number of unicast retries a transmitted frame used. 189 | * 190 | */ 191 | enum ieee80211_radiotap_type { 192 | IEEE80211_RADIOTAP_TSFT = 0, 193 | IEEE80211_RADIOTAP_FLAGS = 1, 194 | IEEE80211_RADIOTAP_RATE = 2, 195 | IEEE80211_RADIOTAP_CHANNEL = 3, 196 | IEEE80211_RADIOTAP_FHSS = 4, 197 | IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5, 198 | IEEE80211_RADIOTAP_DBM_ANTNOISE = 6, 199 | IEEE80211_RADIOTAP_LOCK_QUALITY = 7, 200 | IEEE80211_RADIOTAP_TX_ATTENUATION = 8, 201 | IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9, 202 | IEEE80211_RADIOTAP_DBM_TX_POWER = 10, 203 | IEEE80211_RADIOTAP_ANTENNA = 11, 204 | IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12, 205 | IEEE80211_RADIOTAP_DB_ANTNOISE = 13, 206 | IEEE80211_RADIOTAP_RX_FLAGS = 14, 207 | IEEE80211_RADIOTAP_TX_FLAGS = 15, 208 | IEEE80211_RADIOTAP_RTS_RETRIES = 16, 209 | IEEE80211_RADIOTAP_DATA_RETRIES = 17, 210 | IEEE80211_RADIOTAP_EXT = 31 211 | }; 212 | 213 | /* Channel flags. */ 214 | #define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */ 215 | #define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */ 216 | #define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */ 217 | #define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */ 218 | #define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */ 219 | #define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */ 220 | #define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */ 221 | #define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */ 222 | 223 | /* For IEEE80211_RADIOTAP_FLAGS */ 224 | #define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received 225 | * during CFP 226 | */ 227 | #define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received 228 | * with short 229 | * preamble 230 | */ 231 | #define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received 232 | * with WEP encryption 233 | */ 234 | #define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received 235 | * with fragmentation 236 | */ 237 | #define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */ 238 | #define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between 239 | * 802.11 header and payload 240 | * (to 32-bit boundary) 241 | */ 242 | /* For IEEE80211_RADIOTAP_RX_FLAGS */ 243 | #define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */ 244 | 245 | /* For IEEE80211_RADIOTAP_TX_FLAGS */ 246 | #define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive 247 | * retries */ 248 | #define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */ 249 | #define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */ 250 | 251 | /* Ugly macro to convert literal channel numbers into their mhz equivalents 252 | * There are certianly some conditions that will break this (like feeding it '30') 253 | * but they shouldn't arise since nothing talks on channel 30. */ 254 | #define ieee80211chan2mhz(x) \ 255 | (((x) <= 14) ? \ 256 | (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \ 257 | ((x) + 1000) * 5) 258 | 259 | -------------------------------------------------------------------------------- /lib.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | #include "lib.h" 8 | 9 | 10 | void lib_init_packet_buffer(packet_buffer_t *p) { 11 | assert(p != NULL); 12 | 13 | p->valid = 0; 14 | p->crc_correct = 0; 15 | p->len = 0; 16 | p->data = NULL; 17 | } 18 | 19 | void lib_alloc_packet_buffer(packet_buffer_t *p, size_t len) { 20 | assert(p != NULL); 21 | assert(len > 0); 22 | 23 | p->len = 0; 24 | p->data = (uint8_t*)malloc(len); 25 | } 26 | 27 | void lib_free_packet_buffer(packet_buffer_t *p) { 28 | assert(p != NULL); 29 | 30 | free(p->data); 31 | p->len = 0; 32 | } 33 | 34 | packet_buffer_t *lib_alloc_packet_buffer_list(size_t num_packets, size_t packet_length) { 35 | packet_buffer_t *retval; 36 | int i; 37 | 38 | assert(num_packets > 0 && packet_length > 0); 39 | 40 | retval = (packet_buffer_t *)malloc(sizeof(packet_buffer_t) * num_packets); 41 | assert(retval != NULL); 42 | 43 | for(i=0; i 0); 55 | 56 | for(i=0; i 6 | #include 7 | 8 | #include "wifibroadcast.h" 9 | 10 | typedef struct { 11 | uint32_t received_packet_cnt; 12 | uint32_t wrong_crc_cnt; 13 | int8_t current_signal_dbm; 14 | } wifi_adapter_rx_status_t; 15 | 16 | typedef struct { 17 | time_t last_update; 18 | uint32_t received_block_cnt; 19 | uint32_t damaged_block_cnt; 20 | uint32_t tx_restart_cnt; 21 | 22 | uint32_t wifi_adapter_cnt; 23 | wifi_adapter_rx_status_t adapter[MAX_PENUMBRA_INTERFACES]; 24 | } wifibroadcast_rx_status_t; 25 | 26 | typedef struct { 27 | int valid; 28 | int crc_correct; 29 | size_t len; //this is the actual length of the packet stored in data 30 | uint8_t *data; 31 | } packet_buffer_t; 32 | 33 | 34 | //this sits at the payload of the wifi packet (outside of FEC) 35 | typedef struct { 36 | uint32_t sequence_number; 37 | } __attribute__((packed)) wifi_packet_header_t; 38 | 39 | //this sits at the data payload (which is usually right after the wifi_packet_header_t) (inside of FEC) 40 | typedef struct { 41 | uint32_t data_length; 42 | } __attribute__((packed)) payload_header_t; 43 | 44 | 45 | packet_buffer_t *lib_alloc_packet_buffer_list(size_t num_packets, size_t packet_length); 46 | -------------------------------------------------------------------------------- /patches/AR9271/firmware/LICENCE.TXT: -------------------------------------------------------------------------------- 1 | Files with a Qualcomm Atheros / Atheros licence fall under the following 2 | licence. Please see NOTICES.TXT for information about other files in this 3 | repository. 4 | 5 | ---- 6 | 7 | Copyright (c) 2013 Qualcomm Atheros, Inc. 8 | 9 | All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted (subject to the limitations in the 13 | disclaimer below) provided that the following conditions are met: 14 | 15 | * Redistributions of source code must retain the above copyright 16 | notice, this list of conditions and the following disclaimer. 17 | 18 | * Redistributions in binary form must reproduce the above copyright 19 | notice, this list of conditions and the following disclaimer in the 20 | documentation and/or other materials provided with the 21 | distribution. 22 | 23 | * Neither the name of Qualcomm Atheros nor the names of its 24 | contributors may be used to endorse or promote products derived 25 | from this software without specific prior written permission. 26 | 27 | NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE 28 | GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT 29 | HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 30 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 31 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 32 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 33 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 34 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 35 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 36 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 37 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 38 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 39 | IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 | 41 | ---- 42 | -------------------------------------------------------------------------------- /patches/AR9271/firmware/change_baserate_to_mcs3_26mbits.patch: -------------------------------------------------------------------------------- 1 | From 24c8ae810bf7e232d55113499c6e04630239362b Mon Sep 17 00:00:00 2001 2 | From: befinitiv 3 | Date: Thu, 19 Feb 2015 19:58:15 +0100 4 | Subject: [PATCH] patched firmare to use MCS3 as the base rate 5 | 6 | --- 7 | target_firmware/wlan/ar5416_phy.c | 3 ++- 8 | 1 file changed, 2 insertions(+), 1 deletion(-) 9 | 10 | diff --git a/target_firmware/wlan/ar5416_phy.c b/target_firmware/wlan/ar5416_phy.c 11 | index 4031066..4ad5e03 100755 12 | --- a/target_firmware/wlan/ar5416_phy.c 13 | +++ b/target_firmware/wlan/ar5416_phy.c 14 | @@ -211,6 +211,7 @@ ar5416GetRateTable(struct ath_hal *ah, a_uint32_t mode) 15 | #define TURBO IEEE80211_T_TURBO 16 | #define XR ATHEROS_T_XR 17 | #define HT IEEE80211_T_HT 18 | + // /*[ 0] 1 Mb */ { AH_TRUE, CCK, 1000, 0x1b, 0x00, (0x80| 2), 0 }, 19 | 20 | HAL_RATE_TABLE ar5416_11ng_table = { 21 | 22 | @@ -219,7 +220,7 @@ HAL_RATE_TABLE ar5416_11ng_table = { 23 | { 24 | /* short ctrl */ 25 | /* valid rateCode Preamble dot11Rate Rate */ 26 | - /*[ 0] 1 Mb */ { AH_TRUE, CCK, 1000, 0x1b, 0x00, (0x80| 2), 0 }, 27 | + /*[15] 26 Mb */ { AH_TRUE, HT, 26000, 0x83, 0x00, 3, 8 }, 28 | /*[ 1] 2 Mb */ { AH_TRUE, CCK, 2000, 0x1a, 0x04, (0x80| 4), 1 }, 29 | /*[ 2] 5.5 Mb */ { AH_TRUE, CCK, 5500, 0x19, 0x04, (0x80|11), 2 }, 30 | /*[ 3] 11 Mb */ { AH_TRUE, CCK, 11000, 0x18, 0x04, (0x80|22), 3 }, 31 | -- 32 | 1.9.1 33 | 34 | -------------------------------------------------------------------------------- /patches/AR9271/firmware/htc_9271.fw: -------------------------------------------------------------------------------- 1 | htc_9271.fw.mcs3 -------------------------------------------------------------------------------- /patches/AR9271/firmware/htc_9271.fw.24mbitofdm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/befinitiv/wifibroadcast/e0db6ab23bbc8e16571ee5df19bf9e60aea21ab3/patches/AR9271/firmware/htc_9271.fw.24mbitofdm -------------------------------------------------------------------------------- /patches/AR9271/firmware/htc_9271.fw.mcs1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/befinitiv/wifibroadcast/e0db6ab23bbc8e16571ee5df19bf9e60aea21ab3/patches/AR9271/firmware/htc_9271.fw.mcs1 -------------------------------------------------------------------------------- /patches/AR9271/firmware/htc_9271.fw.mcs3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/befinitiv/wifibroadcast/e0db6ab23bbc8e16571ee5df19bf9e60aea21ab3/patches/AR9271/firmware/htc_9271.fw.mcs3 -------------------------------------------------------------------------------- /patches/AR9271/firmware/readme.txt: -------------------------------------------------------------------------------- 1 | apply the patch to this repo: https://github.com/qca/open-ath9k-htc-firmware.git 2 | 3 | the provided firmware binary is configured to use MCS3 (26mbit/s) as the injection rate 4 | -------------------------------------------------------------------------------- /patches/AR9271/kernel/fixed_channel_power_of_ath9k_to_20dbm.patch: -------------------------------------------------------------------------------- 1 | From 4d02539ecd8b417b7efcc0ebc7617fe11c394085 Mon Sep 17 00:00:00 2001 2 | From: befinitiv 3 | Date: Thu, 19 Feb 2015 20:27:36 +0100 4 | Subject: [PATCH] fixed channel power of ath9k driver to 20dbm 5 | 6 | --- 7 | drivers/net/wireless/ath/ath9k/hw.c | 3 ++- 8 | 1 file changed, 2 insertions(+), 1 deletion(-) 9 | 10 | diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c 11 | index 2ad6057..45fbec3 100644 12 | --- a/drivers/net/wireless/ath/ath9k/hw.c 13 | +++ b/drivers/net/wireless/ath/ath9k/hw.c 14 | @@ -2735,8 +2735,9 @@ void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan, 15 | return; 16 | 17 | channel = chan->chan; 18 | + channel->max_power = 20; 19 | chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER); 20 | - new_pwr = min_t(int, chan_pwr, reg->power_limit); 21 | + new_pwr = chan_pwr; //min_t(int, chan_pwr, reg->power_limit); 22 | max_gain = chan_pwr - new_pwr + channel->max_antenna_gain * 2; 23 | 24 | ant_gain = get_antenna_gain(ah, chan); 25 | -- 26 | 1.9.1 27 | 28 | -------------------------------------------------------------------------------- /patches/AR9271/kernel/readme.txt: -------------------------------------------------------------------------------- 1 | apply this patch to: https://github.com/raspberrypi/linux.git 2 | -------------------------------------------------------------------------------- /radiotap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Radiotap parser 3 | * 4 | * Copyright 2007 Andy Green 5 | */ 6 | 7 | #include "wifibroadcast.h" 8 | #include "radiotap.h" 9 | 10 | /** 11 | * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization 12 | * @iterator: radiotap_iterator to initialize 13 | * @radiotap_header: radiotap header to parse 14 | * @max_length: total length we can parse into (eg, whole packet length) 15 | * 16 | * Returns: 0 or a negative error code if there is a problem. 17 | * 18 | * This function initializes an opaque iterator struct which can then 19 | * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap 20 | * argument which is present in the header. It knows about extended 21 | * present headers and handles them. 22 | * 23 | * How to use: 24 | * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator 25 | * struct ieee80211_radiotap_iterator (no need to init the struct beforehand) 26 | * checking for a good 0 return code. Then loop calling 27 | * __ieee80211_radiotap_iterator_next()... it returns either 0, 28 | * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem. 29 | * The iterator's @this_arg member points to the start of the argument 30 | * associated with the current argument index that is present, which can be 31 | * found in the iterator's @this_arg_index member. This arg index corresponds 32 | * to the IEEE80211_RADIOTAP_... defines. 33 | * 34 | * Radiotap header length: 35 | * You can find the CPU-endian total radiotap header length in 36 | * iterator->max_length after executing ieee80211_radiotap_iterator_init() 37 | * successfully. 38 | * 39 | * Example code: 40 | * See Documentation/networking/radiotap-headers.txt 41 | */ 42 | 43 | int ieee80211_radiotap_iterator_init( 44 | struct ieee80211_radiotap_iterator *iterator, 45 | struct ieee80211_radiotap_header *radiotap_header, 46 | int max_length) 47 | { 48 | /* Linux only supports version 0 radiotap format */ 49 | if (radiotap_header->it_version) 50 | return -EINVAL; 51 | 52 | /* sanity check for allowed length and radiotap length field */ 53 | if (max_length < le16_to_cpu(radiotap_header->it_len)) 54 | return -EINVAL; 55 | 56 | iterator->rtheader = radiotap_header; 57 | iterator->max_length = le16_to_cpu(radiotap_header->it_len); 58 | iterator->arg_index = 0; 59 | iterator->bitmap_shifter = le32_to_cpu(radiotap_header->it_present); 60 | iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header); 61 | iterator->this_arg = 0; 62 | 63 | /* find payload start allowing for extended bitmap(s) */ 64 | 65 | if (unlikely(iterator->bitmap_shifter & (1<arg)) & 67 | (1<arg += sizeof(u32); 69 | 70 | /* 71 | * check for insanity where the present bitmaps 72 | * keep claiming to extend up to or even beyond the 73 | * stated radiotap header length 74 | */ 75 | 76 | if (((ulong)iterator->arg - 77 | (ulong)iterator->rtheader) > iterator->max_length) 78 | return -EINVAL; 79 | } 80 | 81 | iterator->arg += sizeof(u32); 82 | 83 | /* 84 | * no need to check again for blowing past stated radiotap 85 | * header length, because ieee80211_radiotap_iterator_next 86 | * checks it before it is dereferenced 87 | */ 88 | } 89 | 90 | /* we are all initialized happily */ 91 | 92 | return 0; 93 | } 94 | 95 | 96 | /** 97 | * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg 98 | * @iterator: radiotap_iterator to move to next arg (if any) 99 | * 100 | * Returns: 0 if there is an argument to handle, 101 | * -ENOENT if there are no more args or -EINVAL 102 | * if there is something else wrong. 103 | * 104 | * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*) 105 | * in @this_arg_index and sets @this_arg to point to the 106 | * payload for the field. It takes care of alignment handling and extended 107 | * present fields. @this_arg can be changed by the caller (eg, 108 | * incremented to move inside a compound argument like 109 | * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in 110 | * little-endian format whatever the endianess of your CPU. 111 | */ 112 | 113 | int ieee80211_radiotap_iterator_next( 114 | struct ieee80211_radiotap_iterator *iterator) 115 | { 116 | 117 | /* 118 | * small length lookup table for all radiotap types we heard of 119 | * starting from b0 in the bitmap, so we can walk the payload 120 | * area of the radiotap header 121 | * 122 | * There is a requirement to pad args, so that args 123 | * of a given length must begin at a boundary of that length 124 | * -- but note that compound args are allowed (eg, 2 x u16 125 | * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not 126 | * a reliable indicator of alignment requirement. 127 | * 128 | * upper nybble: content alignment for arg 129 | * lower nybble: content length for arg 130 | */ 131 | 132 | static const u8 rt_sizes[] = { 133 | [IEEE80211_RADIOTAP_TSFT] = 0x88, 134 | [IEEE80211_RADIOTAP_FLAGS] = 0x11, 135 | [IEEE80211_RADIOTAP_RATE] = 0x11, 136 | [IEEE80211_RADIOTAP_CHANNEL] = 0x24, 137 | [IEEE80211_RADIOTAP_FHSS] = 0x22, 138 | [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11, 139 | [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11, 140 | [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22, 141 | [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22, 142 | [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22, 143 | [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11, 144 | [IEEE80211_RADIOTAP_ANTENNA] = 0x11, 145 | [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11, 146 | [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11 147 | /* 148 | * add more here as they are defined in 149 | * include/net/ieee80211_radiotap.h 150 | */ 151 | }; 152 | 153 | /* 154 | * for every radiotap entry we can at 155 | * least skip (by knowing the length)... 156 | */ 157 | 158 | while (iterator->arg_index < sizeof(rt_sizes)) { 159 | int hit = 0; 160 | int pad; 161 | 162 | if (!(iterator->bitmap_shifter & 1)) 163 | goto next_entry; /* arg not present */ 164 | 165 | /* 166 | * arg is present, account for alignment padding 167 | * 8-bit args can be at any alignment 168 | * 16-bit args must start on 16-bit boundary 169 | * 32-bit args must start on 32-bit boundary 170 | * 64-bit args must start on 64-bit boundary 171 | * 172 | * note that total arg size can differ from alignment of 173 | * elements inside arg, so we use upper nybble of length 174 | * table to base alignment on 175 | * 176 | * also note: these alignments are ** relative to the 177 | * start of the radiotap header **. There is no guarantee 178 | * that the radiotap header itself is aligned on any 179 | * kind of boundary. 180 | */ 181 | 182 | pad = (((ulong)iterator->arg) - 183 | ((ulong)iterator->rtheader)) & 184 | ((rt_sizes[iterator->arg_index] >> 4) - 1); 185 | 186 | if (pad) 187 | iterator->arg += 188 | (rt_sizes[iterator->arg_index] >> 4) - pad; 189 | 190 | /* 191 | * this is what we will return to user, but we need to 192 | * move on first so next call has something fresh to test 193 | */ 194 | iterator->this_arg_index = iterator->arg_index; 195 | iterator->this_arg = iterator->arg; 196 | hit = 1; 197 | 198 | /* internally move on the size of this arg */ 199 | iterator->arg += rt_sizes[iterator->arg_index] & 0x0f; 200 | 201 | /* 202 | * check for insanity where we are given a bitmap that 203 | * claims to have more arg content than the length of the 204 | * radiotap section. We will normally end up equalling this 205 | * max_length on the last arg, never exceeding it. 206 | */ 207 | 208 | if (((ulong)iterator->arg - (ulong)iterator->rtheader) > 209 | iterator->max_length) 210 | return -EINVAL; 211 | 212 | next_entry: 213 | iterator->arg_index++; 214 | if (unlikely((iterator->arg_index & 31) == 0)) { 215 | /* completed current u32 bitmap */ 216 | if (iterator->bitmap_shifter & 1) { 217 | /* b31 was set, there is more */ 218 | /* move to next u32 bitmap */ 219 | iterator->bitmap_shifter = 220 | le32_to_cpu(*iterator->next_bitmap); 221 | iterator->next_bitmap++; 222 | } else { 223 | /* no more bitmaps: end */ 224 | iterator->arg_index = sizeof(rt_sizes); 225 | } 226 | } else { /* just try the next bit */ 227 | iterator->bitmap_shifter >>= 1; 228 | } 229 | 230 | /* if we found a valid arg earlier, return it now */ 231 | if (hit) 232 | return 0; 233 | } 234 | 235 | /* we don't know how to handle any more args, we're done */ 236 | return -ENOENT; 237 | } 238 | 239 | -------------------------------------------------------------------------------- /radiotap.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "ieee80211_radiotap.h" 4 | 5 | /* Radiotap header iteration 6 | * implemented in net/wireless/radiotap.c 7 | * docs in Documentation/networking/radiotap-headers.txt 8 | */ 9 | /** 10 | * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args 11 | * @rtheader: pointer to the radiotap header we are walking through 12 | * @max_length: length of radiotap header in cpu byte ordering 13 | * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg 14 | * @this_arg: pointer to current radiotap arg 15 | * @arg_index: internal next argument index 16 | * @arg: internal next argument pointer 17 | * @next_bitmap: internal pointer to next present u32 18 | * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present 19 | */ 20 | 21 | struct ieee80211_radiotap_iterator { 22 | struct ieee80211_radiotap_header *rtheader; 23 | int max_length; 24 | int this_arg_index; 25 | u8 *this_arg; 26 | 27 | int arg_index; 28 | u8 *arg; 29 | __le32 *next_bitmap; 30 | u32 bitmap_shifter; 31 | }; 32 | 33 | extern int ieee80211_radiotap_iterator_init( 34 | struct ieee80211_radiotap_iterator *iterator, 35 | struct ieee80211_radiotap_header *radiotap_header, 36 | int max_length); 37 | 38 | extern int ieee80211_radiotap_iterator_next( 39 | struct ieee80211_radiotap_iterator *iterator); 40 | 41 | -------------------------------------------------------------------------------- /rx.c: -------------------------------------------------------------------------------- 1 | // (c)2015 befinitiv 2 | 3 | /* 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; version 2. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along 14 | * with this program; if not, write to the Free Software Foundation, Inc., 15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | 19 | #include "fec.h" 20 | 21 | 22 | #include "lib.h" 23 | #include "wifibroadcast.h" 24 | #include "radiotap.h" 25 | 26 | #include 27 | 28 | #define MAX_PACKET_LENGTH 4192 29 | #define MAX_USER_PACKET_LENGTH 1450 30 | #define MAX_DATA_OR_FEC_PACKETS_PER_BLOCK 32 31 | 32 | #define DEBUG 0 33 | #define debug_print(fmt, ...) \ 34 | do { if (DEBUG) fprintf(stderr, fmt, __VA_ARGS__); } while (0) 35 | 36 | 37 | 38 | 39 | 40 | // this is where we store a summary of the 41 | // information from the radiotap header 42 | 43 | typedef struct { 44 | int m_nChannel; 45 | int m_nChannelFlags; 46 | int m_nRate; 47 | int m_nAntenna; 48 | int m_nRadiotapFlags; 49 | } __attribute__((packed)) PENUMBRA_RADIOTAP_DATA; 50 | 51 | 52 | 53 | int flagHelp = 0; 54 | int param_port = 0; 55 | int param_data_packets_per_block = 8; 56 | int param_fec_packets_per_block = 4; 57 | int param_block_buffers = 1; 58 | int param_packet_length = MAX_USER_PACKET_LENGTH; 59 | wifibroadcast_rx_status_t *rx_status = NULL; 60 | int max_block_num = -1; 61 | 62 | void 63 | usage(void) 64 | { 65 | printf( 66 | "(c)2015 befinitiv. Based on packetspammer by Andy Green. Licensed under GPL2\n" 67 | "\n" 68 | "Usage: rx [options] \n\nOptions\n" 69 | "-p Port number 0-255 (default 0)\n" 70 | "-b Number of data packets in a block (default 8). Needs to match with tx.\n" 71 | "-r Number of FEC packets per block (default 4). Needs to match with tx.\n\n" 72 | "-f Number of bytes per packet (default %d. max %d). This is also the FEC block size. Needs to match with tx\n" 73 | "-d Number of transmissions blocks that are buffered (default 1). This is needed in case of diversity if one adapter delivers data faster than the other. Note that this increases latency\n" 74 | "Example:\n" 75 | " iwconfig wlan0 down\n" 76 | " iw dev wlan0 set monitor otherbss fcsfail\n" 77 | " ifconfig wlan0 up\n" 78 | " iwconfig wlan0 channel 13\n" 79 | " rx wlan0 Receive raw packets on wlan0 and output the payload to stdout\n" 80 | "\n", MAX_USER_PACKET_LENGTH, MAX_USER_PACKET_LENGTH); 81 | exit(1); 82 | } 83 | 84 | typedef struct { 85 | pcap_t *ppcap; 86 | int selectable_fd; 87 | int n80211HeaderLength; 88 | } monitor_interface_t; 89 | 90 | typedef struct { 91 | int block_num; 92 | packet_buffer_t *packet_buffer_list; 93 | } block_buffer_t; 94 | 95 | void open_and_configure_interface(const char *name, int port, monitor_interface_t *interface) { 96 | struct bpf_program bpfprogram; 97 | char szProgram[512]; 98 | char szErrbuf[PCAP_ERRBUF_SIZE]; 99 | // open the interface in pcap 100 | 101 | szErrbuf[0] = '\0'; 102 | interface->ppcap = pcap_open_live(name, 2048, 1, -1, szErrbuf); 103 | if (interface->ppcap == NULL) { 104 | fprintf(stderr, "Unable to open interface %s in pcap: %s\n", 105 | name, szErrbuf); 106 | exit(1); 107 | } 108 | 109 | 110 | if(pcap_setnonblock(interface->ppcap, 1, szErrbuf) < 0) { 111 | fprintf(stderr, "Error setting %s to nonblocking mode: %s\n", name, szErrbuf); 112 | } 113 | 114 | int nLinkEncap = pcap_datalink(interface->ppcap); 115 | 116 | switch (nLinkEncap) { 117 | 118 | case DLT_PRISM_HEADER: 119 | fprintf(stderr, "DLT_PRISM_HEADER Encap\n"); 120 | interface->n80211HeaderLength = 0x20; // ieee80211 comes after this 121 | sprintf(szProgram, "radio[0x4a:4]==0x13223344 && radio[0x4e:2] == 0x55%.2x", port); 122 | break; 123 | 124 | case DLT_IEEE802_11_RADIO: 125 | fprintf(stderr, "DLT_IEEE802_11_RADIO Encap\n"); 126 | interface->n80211HeaderLength = 0x18; // ieee80211 comes after this 127 | sprintf(szProgram, "ether[0x0a:4]==0x13223344 && ether[0x0e:2] == 0x55%.2x", port); 128 | break; 129 | 130 | default: 131 | fprintf(stderr, "!!! unknown encapsulation on %s !\n", name); 132 | exit(1); 133 | 134 | } 135 | 136 | if (pcap_compile(interface->ppcap, &bpfprogram, szProgram, 1, 0) == -1) { 137 | puts(szProgram); 138 | puts(pcap_geterr(interface->ppcap)); 139 | exit(1); 140 | } else { 141 | if (pcap_setfilter(interface->ppcap, &bpfprogram) == -1) { 142 | fprintf(stderr, "%s\n", szProgram); 143 | fprintf(stderr, "%s\n", pcap_geterr(interface->ppcap)); 144 | } else { 145 | } 146 | pcap_freecode(&bpfprogram); 147 | } 148 | 149 | interface->selectable_fd = pcap_get_selectable_fd(interface->ppcap); 150 | } 151 | 152 | 153 | void block_buffer_list_reset(block_buffer_t *block_buffer_list, size_t block_buffer_list_len, int block_buffer_len) { 154 | int i; 155 | block_buffer_t *rb = block_buffer_list; 156 | 157 | for(i=0; iblock_num = -1; 159 | 160 | int j; 161 | packet_buffer_t *p = rb->packet_buffer_list; 162 | for(j=0; jvalid = 0; 164 | p->crc_correct = 0; 165 | p->len = 0; 166 | p++; 167 | } 168 | 169 | rb++; 170 | } 171 | } 172 | 173 | void process_payload(uint8_t *data, size_t data_len, int crc_correct, block_buffer_t *block_buffer_list, int adapter_no) 174 | { 175 | wifi_packet_header_t *wph; 176 | int block_num; 177 | int packet_num; 178 | int i; 179 | 180 | wph = (wifi_packet_header_t*)data; 181 | data += sizeof(wifi_packet_header_t); 182 | data_len -= sizeof(wifi_packet_header_t); 183 | 184 | block_num = wph->sequence_number / (param_data_packets_per_block+param_fec_packets_per_block);//if aram_data_packets_per_block+param_fec_packets_per_block would be limited to powers of two, this could be replaced by a logical AND operation 185 | 186 | //debug_print("adap %d rec %x blk %x crc %d len %d\n", adapter_no, wph->sequence_number, block_num, crc_correct, data_len); 187 | 188 | 189 | //we have received a block number that exceeds the currently seen ones -> we need to make room for this new block 190 | //or we have received a block_num that is several times smaller than the current window of buffers -> this indicated that either the window is too small or that the transmitter has been restarted 191 | int tx_restart = (block_num + 128*param_block_buffers < max_block_num); 192 | if((block_num > max_block_num || tx_restart) && crc_correct) { 193 | if(tx_restart) { 194 | rx_status->tx_restart_cnt++; 195 | 196 | fprintf(stderr, "TX RESTART: Detected blk %x that lies outside of the current retr block buffer window (max_block_num = %x) (if there was no tx restart, increase window size via -d)\n", block_num, max_block_num); 197 | 198 | 199 | block_buffer_list_reset(block_buffer_list, param_block_buffers, param_data_packets_per_block + param_fec_packets_per_block); 200 | } 201 | 202 | //first, find the minimum block num in the buffers list. this will be the block that we replace 203 | int min_block_num = INT_MAX; 204 | int min_block_num_idx; 205 | for(i=0; ireceived_block_cnt++; 219 | 220 | //we have both pointers to the packet buffers (to get information about crc and vadility) and raw data pointers for fec_decode 221 | packet_buffer_t *data_pkgs[MAX_DATA_OR_FEC_PACKETS_PER_BLOCK]; 222 | packet_buffer_t *fec_pkgs[MAX_DATA_OR_FEC_PACKETS_PER_BLOCK]; 223 | uint8_t *data_blocks[MAX_DATA_OR_FEC_PACKETS_PER_BLOCK]; 224 | uint8_t *fec_blocks[MAX_DATA_OR_FEC_PACKETS_PER_BLOCK]; 225 | int datas_missing = 0, datas_corrupt = 0, fecs_missing = 0, fecs_corrupt = 0; 226 | int di = 0, fi = 0; 227 | 228 | 229 | //first, split the received packets into DATA a FEC packets and count the damaged packets 230 | i = 0; 231 | while(di < param_data_packets_per_block || fi < param_fec_packets_per_block) { 232 | if(di < param_data_packets_per_block) { 233 | data_pkgs[di] = packet_buffer_list + i++; 234 | data_blocks[di] = data_pkgs[di]->data; 235 | if(!data_pkgs[di]->valid) 236 | datas_missing++; 237 | if(data_pkgs[di]->valid && !data_pkgs[di]->crc_correct) 238 | datas_corrupt++; 239 | di++; 240 | } 241 | 242 | if(fi < param_fec_packets_per_block) { 243 | fec_pkgs[fi] = packet_buffer_list + i++; 244 | if(!fec_pkgs[fi]->valid) 245 | fecs_missing++; 246 | 247 | if(fec_pkgs[fi]->valid && !fec_pkgs[fi]->crc_correct) 248 | fecs_corrupt++; 249 | 250 | fi++; 251 | } 252 | } 253 | 254 | const int good_fecs_c = param_fec_packets_per_block - fecs_missing - fecs_corrupt; 255 | const int datas_missing_c = datas_missing; 256 | const int datas_corrupt_c = datas_corrupt; 257 | const int fecs_missing_c = fecs_missing; 258 | const int fecs_corrupt_c = fecs_corrupt; 259 | 260 | int good_fecs = good_fecs_c; 261 | //the following three fields are infos for fec_decode 262 | unsigned int fec_block_nos[MAX_DATA_OR_FEC_PACKETS_PER_BLOCK]; 263 | unsigned int erased_blocks[MAX_DATA_OR_FEC_PACKETS_PER_BLOCK]; 264 | unsigned int nr_fec_blocks = 0; 265 | 266 | 267 | #if DEBUG 268 | if(datas_missing_c + datas_corrupt_c > good_fecs_c) { 269 | int x; 270 | 271 | for(x=0;xvalid) { 273 | if(data_pkgs[x]->crc_correct) 274 | fprintf(stderr, "v"); 275 | else 276 | fprintf(stderr, "c"); 277 | } 278 | else 279 | fprintf(stderr, "m"); 280 | } 281 | 282 | fprintf(stderr, " "); 283 | 284 | for(x=0;xvalid) { 286 | if(fec_pkgs[x]->crc_correct) 287 | fprintf(stderr, "v"); 288 | else 289 | fprintf(stderr, "c"); 290 | } 291 | else 292 | fprintf(stderr, "m"); 293 | } 294 | 295 | fprintf(stderr, "\n"); 296 | } 297 | #endif 298 | 299 | fi = 0; 300 | di = 0; 301 | 302 | //look for missing DATA and replace them with good FECs 303 | while(di < param_data_packets_per_block && fi < param_fec_packets_per_block) { 304 | //if this data is fine we go to the next 305 | if(data_pkgs[di]->valid && data_pkgs[di]->crc_correct) { 306 | di++; 307 | continue; 308 | } 309 | 310 | //if this DATA is corrupt and there are less good fecs than missing datas we cannot do anything for this data 311 | if(data_pkgs[di]->valid && !data_pkgs[di]->crc_correct && good_fecs <= datas_missing) { 312 | di++; 313 | continue; 314 | } 315 | 316 | //if this FEC is not received we go on to the next 317 | if(!fec_pkgs[fi]->valid) { 318 | fi++; 319 | continue; 320 | } 321 | 322 | //if this FEC is corrupted and there are more lost packages than good fecs we should replace this DATA even with this corrupted FEC 323 | if(!fec_pkgs[fi]->crc_correct && datas_missing > good_fecs) { 324 | fi++; 325 | continue; 326 | } 327 | 328 | 329 | if(!data_pkgs[di]->valid) 330 | datas_missing--; 331 | else if(!data_pkgs[di]->crc_correct) 332 | datas_corrupt--; 333 | 334 | if(fec_pkgs[fi]->crc_correct) 335 | good_fecs--; 336 | 337 | //at this point, data is invalid and fec is good -> replace data with fec 338 | erased_blocks[nr_fec_blocks] = di; 339 | fec_block_nos[nr_fec_blocks] = fi; 340 | fec_blocks[nr_fec_blocks] = fec_pkgs[fi]->data; 341 | di++; 342 | fi++; 343 | nr_fec_blocks++; 344 | } 345 | 346 | 347 | int reconstruction_failed = datas_missing_c + datas_corrupt_c > good_fecs_c; 348 | 349 | if(reconstruction_failed) { 350 | //we did not have enough FEC packets to repair this block 351 | rx_status->damaged_block_cnt++; 352 | fprintf(stderr, "Could not fully reconstruct block %x! Damage rate: %f (%d / %d blocks)\n", last_block_num, 1.0 * rx_status->damaged_block_cnt / rx_status->received_block_cnt, rx_status->damaged_block_cnt, rx_status->received_block_cnt); 353 | debug_print("Data mis: %d\tData corr: %d\tFEC mis: %d\tFEC corr: %d\n", datas_missing_c, datas_corrupt_c, fecs_missing_c, fecs_corrupt_c); 354 | } 355 | 356 | 357 | //decode data and write it to STDOUT 358 | fec_decode((unsigned int) param_packet_length, data_blocks, param_data_packets_per_block, fec_blocks, fec_block_nos, erased_blocks, nr_fec_blocks); 359 | for(i=0; ivalid) { 363 | //if reconstruction did fail, the data_length value is undefined. better limit it to some sensible value 364 | if(ph->data_length > param_packet_length) 365 | ph->data_length = param_packet_length; 366 | 367 | write(STDOUT_FILENO, data_blocks[i] + sizeof(payload_header_t), ph->data_length); 368 | } 369 | } 370 | 371 | 372 | //reset buffers 373 | for(i=0; ivalid = 0; 376 | p->crc_correct = 0; 377 | p->len = 0; 378 | } 379 | } 380 | 381 | block_buffer_list[min_block_num_idx].block_num = block_num; 382 | max_block_num = block_num; 383 | } 384 | 385 | 386 | //find the buffer into which we have to write this packet 387 | block_buffer_t *rbb = block_buffer_list; 388 | for(i=0; iblock_num == block_num) { 390 | break; 391 | } 392 | rbb++; 393 | } 394 | 395 | //check if we have actually found the corresponding block. this could not be the case due to a corrupt packet 396 | if(i != param_block_buffers) { 397 | packet_buffer_t *packet_buffer_list = rbb->packet_buffer_list; 398 | packet_num = wph->sequence_number % (param_data_packets_per_block+param_fec_packets_per_block); //if retr_block_size would be limited to powers of two, this could be replace by a locical and operation 399 | 400 | //only overwrite packets where the checksum is not yet correct. otherwise the packets are already received correctly 401 | if(packet_buffer_list[packet_num].crc_correct == 0) { 402 | memcpy(packet_buffer_list[packet_num].data, data, data_len); 403 | packet_buffer_list[packet_num].len = data_len; 404 | packet_buffer_list[packet_num].valid = 1; 405 | packet_buffer_list[packet_num].crc_correct = crc_correct; 406 | } 407 | } 408 | 409 | } 410 | 411 | 412 | void process_packet(monitor_interface_t *interface, block_buffer_t *block_buffer_list, int adapter_no) { 413 | struct pcap_pkthdr * ppcapPacketHeader = NULL; 414 | struct ieee80211_radiotap_iterator rti; 415 | PENUMBRA_RADIOTAP_DATA prd; 416 | u8 payloadBuffer[MAX_PACKET_LENGTH]; 417 | u8 *pu8Payload = payloadBuffer; 418 | int bytes; 419 | int n; 420 | int retval; 421 | int u16HeaderLen; 422 | 423 | // receive 424 | 425 | 426 | retval = pcap_next_ex(interface->ppcap, &ppcapPacketHeader, 427 | (const u_char**)&pu8Payload); 428 | 429 | if (retval < 0) { 430 | fprintf(stderr, "Socket broken\n"); 431 | fprintf(stderr, "%s\n", pcap_geterr(interface->ppcap)); 432 | exit(1); 433 | } 434 | 435 | //if(retval == 0) 436 | // fprintf(stderr, "retval = 0\n"); 437 | 438 | if (retval != 1) 439 | return; 440 | 441 | 442 | u16HeaderLen = (pu8Payload[2] + (pu8Payload[3] << 8)); 443 | 444 | if (ppcapPacketHeader->len < 445 | (u16HeaderLen + interface->n80211HeaderLength)) 446 | return; 447 | 448 | bytes = ppcapPacketHeader->len - 449 | (u16HeaderLen + interface->n80211HeaderLength); 450 | if (bytes < 0) 451 | return; 452 | 453 | if (ieee80211_radiotap_iterator_init(&rti, 454 | (struct ieee80211_radiotap_header *)pu8Payload, 455 | ppcapPacketHeader->len) < 0) 456 | return; 457 | 458 | while ((n = ieee80211_radiotap_iterator_next(&rti)) == 0) { 459 | 460 | switch (rti.this_arg_index) { 461 | case IEEE80211_RADIOTAP_RATE: 462 | prd.m_nRate = (*rti.this_arg); 463 | break; 464 | 465 | case IEEE80211_RADIOTAP_CHANNEL: 466 | prd.m_nChannel = 467 | le16_to_cpu(*((u16 *)rti.this_arg)); 468 | prd.m_nChannelFlags = 469 | le16_to_cpu(*((u16 *)(rti.this_arg + 2))); 470 | break; 471 | 472 | case IEEE80211_RADIOTAP_ANTENNA: 473 | prd.m_nAntenna = (*rti.this_arg) + 1; 474 | break; 475 | 476 | case IEEE80211_RADIOTAP_FLAGS: 477 | prd.m_nRadiotapFlags = *rti.this_arg; 478 | break; 479 | 480 | case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: 481 | rx_status->adapter[adapter_no].current_signal_dbm = (int8_t)(*rti.this_arg); 482 | break; 483 | 484 | } 485 | } 486 | pu8Payload += u16HeaderLen + interface->n80211HeaderLength; 487 | 488 | if (prd.m_nRadiotapFlags & IEEE80211_RADIOTAP_F_FCS) 489 | bytes -= 4; 490 | 491 | 492 | int checksum_correct = (prd.m_nRadiotapFlags & 0x40) == 0; 493 | 494 | if(!checksum_correct) 495 | rx_status->adapter[adapter_no].wrong_crc_cnt++; 496 | 497 | rx_status->adapter[adapter_no].received_packet_cnt++; 498 | 499 | if(rx_status->adapter[adapter_no].received_packet_cnt % 1024 == 0) { 500 | fprintf(stderr, "Signal (card %d): %ddBm\n", adapter_no, rx_status->adapter[adapter_no].current_signal_dbm); 501 | } 502 | 503 | rx_status->last_update = time(NULL); 504 | 505 | process_payload(pu8Payload, bytes, checksum_correct, block_buffer_list, adapter_no); 506 | } 507 | 508 | 509 | 510 | void status_memory_init(wifibroadcast_rx_status_t *s) { 511 | s->received_block_cnt = 0; 512 | s->damaged_block_cnt = 0; 513 | s->tx_restart_cnt = 0; 514 | s->wifi_adapter_cnt = 0; 515 | 516 | int i; 517 | for(i=0; iadapter[i].received_packet_cnt = 0; 519 | s->adapter[i].wrong_crc_cnt = 0; 520 | s->adapter[i].current_signal_dbm = 0; 521 | } 522 | } 523 | 524 | 525 | wifibroadcast_rx_status_t *status_memory_open(void) { 526 | char buf[128]; 527 | int fd; 528 | 529 | sprintf(buf, "/wifibroadcast_rx_status_%d", param_port); 530 | fd = shm_open(buf, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); 531 | 532 | if(fd < 0) { 533 | perror("shm_open"); 534 | exit(1); 535 | } 536 | 537 | if (ftruncate(fd, sizeof(wifibroadcast_rx_status_t)) == -1) { 538 | perror("ftruncate"); 539 | exit(1); 540 | } 541 | 542 | void *retval = mmap(NULL, sizeof(wifibroadcast_rx_status_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 543 | if (retval == MAP_FAILED) { 544 | perror("mmap"); 545 | exit(1); 546 | } 547 | 548 | wifibroadcast_rx_status_t *tretval = (wifibroadcast_rx_status_t*)retval; 549 | status_memory_init(tretval); 550 | 551 | return tretval; 552 | 553 | } 554 | 555 | int 556 | main(int argc, char *argv[]) 557 | { 558 | monitor_interface_t interfaces[MAX_PENUMBRA_INTERFACES]; 559 | int num_interfaces = 0; 560 | int i; 561 | 562 | block_buffer_t *block_buffer_list; 563 | 564 | 565 | while (1) { 566 | int nOptionIndex; 567 | static const struct option optiona[] = { 568 | { "help", no_argument, &flagHelp, 1 }, 569 | { 0, 0, 0, 0 } 570 | }; 571 | int c = getopt_long(argc, argv, "hp:b:d:r:f:", 572 | optiona, &nOptionIndex); 573 | 574 | if (c == -1) 575 | break; 576 | switch (c) { 577 | case 0: // long option 578 | break; 579 | 580 | case 'h': // help 581 | usage(); 582 | 583 | case 'p': //port 584 | param_port = atoi(optarg); 585 | break; 586 | 587 | case 'b': 588 | param_data_packets_per_block = atoi(optarg); 589 | break; 590 | 591 | case 'r': 592 | param_fec_packets_per_block = atoi(optarg); 593 | break; 594 | 595 | case 'd': 596 | param_block_buffers = atoi(optarg); 597 | break; 598 | 599 | case 'f': // MTU 600 | param_packet_length = atoi(optarg); 601 | break; 602 | 603 | default: 604 | fprintf(stderr, "unknown switch %c\n", c); 605 | usage(); 606 | break; 607 | } 608 | } 609 | 610 | if (optind >= argc) 611 | usage(); 612 | 613 | 614 | if(param_packet_length > MAX_USER_PACKET_LENGTH) { 615 | printf("Packet length is limited to %d bytes (you requested %d bytes)\n", MAX_USER_PACKET_LENGTH, param_packet_length); 616 | return (1); 617 | } 618 | 619 | 620 | fec_init(); 621 | 622 | int x = optind; 623 | while(x < argc && num_interfaces < MAX_PENUMBRA_INTERFACES) { 624 | open_and_configure_interface(argv[x], param_port, interfaces + num_interfaces); 625 | ++num_interfaces; 626 | ++x; 627 | } 628 | 629 | 630 | //block buffers contain both the block_num as well as packet buffers for a block. 631 | block_buffer_list = malloc(sizeof(block_buffer_t) * param_block_buffers); 632 | for(i=0; iwifi_adapter_cnt = num_interfaces; 641 | 642 | for(;;) { 643 | fd_set readset; 644 | struct timeval to; 645 | 646 | to.tv_sec = 0; 647 | to.tv_usec = 1e5; 648 | 649 | FD_ZERO(&readset); 650 | for(i=0; i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "lib.h" 15 | 16 | wifibroadcast_rx_status_t *status_memory_open(void) { 17 | int fd = shm_open("/wifibroadcast_rx_status_0", O_RDWR, S_IRUSR | S_IWUSR); 18 | 19 | if(fd < 0) { 20 | perror("shm_open"); 21 | exit(1); 22 | } 23 | 24 | if (ftruncate(fd, sizeof(wifibroadcast_rx_status_t)) == -1) { 25 | perror("ftruncate"); 26 | exit(1); 27 | } 28 | 29 | void *retval = mmap(NULL, sizeof(wifibroadcast_rx_status_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 30 | if (retval == MAP_FAILED) { 31 | perror("mmap"); 32 | exit(1); 33 | } 34 | 35 | 36 | return (wifibroadcast_rx_status_t*)retval; 37 | 38 | } 39 | 40 | 41 | int main(void) { 42 | 43 | wifibroadcast_rx_status_t *t = status_memory_open(); 44 | 45 | for(;;) { 46 | printf("\033[2J\r"); 47 | printf("Card 0\n------\n"); 48 | printf("Signal:\t\t\t%ddBm\n", t->adapter[0].current_signal_dbm); 49 | printf("Received Pkg:\t\t%d\n", t->adapter[0].received_packet_cnt); 50 | printf("Wrong CRC ad0:\t\t%d\n", t->adapter[0].wrong_crc_cnt); 51 | printf("\nWifibroadcast\n-------------\n"); 52 | printf("Wifi cards:\t\t%d\n", t->wifi_adapter_cnt); 53 | printf("Received Blocks:\t\t%d\n", t->received_block_cnt); 54 | printf("Damaged Blocks:\t\t%d\n", t->damaged_block_cnt); 55 | printf("TX restarts:\t\t%dn", t->tx_restart_cnt); 56 | usleep(1e5); 57 | } 58 | 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /tx.c: -------------------------------------------------------------------------------- 1 | // (c)2015 befinitiv 2 | 3 | /* 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; version 2. 7 | * 8 | * This program is distributed in the hope that it will be useful, 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | * GNU General Public License for more details. 12 | * 13 | * You should have received a copy of the GNU General Public License along 14 | * with this program; if not, write to the Free Software Foundation, Inc., 15 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | */ 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include "fec.h" 26 | 27 | #include "lib.h" 28 | #include "wifibroadcast.h" 29 | 30 | 31 | 32 | #define MAX_PACKET_LENGTH 4192 33 | #define MAX_USER_PACKET_LENGTH 1450 34 | #define MAX_DATA_OR_FEC_PACKETS_PER_BLOCK 32 35 | 36 | #define FIFO_NAME "/tmp/fifo%d" 37 | #define MAX_FIFOS 8 38 | 39 | 40 | /* this is the template radiotap header we send packets out with */ 41 | 42 | static const u8 u8aRadiotapHeader[] = { 43 | 44 | 0x00, 0x00, // <-- radiotap version 45 | 0x0c, 0x00, // <- radiotap header lengt 46 | 0x04, 0x80, 0x00, 0x00, // <-- bitmap 47 | 0x22, 48 | 0x0, 49 | 0x18, 0x00 50 | }; 51 | 52 | /* Penumbra IEEE80211 header */ 53 | 54 | //the last byte of the mac address is recycled as a port number 55 | #define SRC_MAC_LASTBYTE 15 56 | #define DST_MAC_LASTBYTE 21 57 | 58 | static u8 u8aIeeeHeader[] = { 59 | 0x08, 0x01, 0x00, 0x00, 60 | 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 61 | 0x13, 0x22, 0x33, 0x44, 0x55, 0x66, 62 | 0x13, 0x22, 0x33, 0x44, 0x55, 0x66, 63 | 0x10, 0x86, 64 | }; 65 | 66 | 67 | 68 | int flagHelp = 0; 69 | 70 | 71 | 72 | void 73 | usage(void) 74 | { 75 | printf( 76 | "(c)2015 befinitiv. Based on packetspammer by Andy Green. Licensed under GPL2\n" 77 | "\n" 78 | "Usage: tx [options] \n\nOptions\n" 79 | "-r Number of FEC packets per block (default 4). Needs to match with rx.\n\n" 80 | "-f Number of bytes per packet (default %d. max %d). This is also the FEC block size. Needs to match with rx\n" 81 | "-p Port number 0-255 (default 0)\n" 82 | "-b Number of data packets in a block (default 8). Needs to match with rx.\n" 83 | "-x Number of transmissions of a block (default 1)\n" 84 | "-m Minimum number of bytes per frame (default: 0)\n" 85 | "-s If is > 1 then the parameter changes \"tx\" input from stdin to named fifos. Each fifo transports a stream over a different port (starting at -p port and incrementing). Fifo names are \"%s\". (default 1)\n" 86 | "Example:\n" 87 | " iwconfig wlan0 down\n" 88 | " iw dev wlan0 set monitor otherbss fcsfail\n" 89 | " ifconfig wlan0 up\n" 90 | " iwconfig wlan0 channel 13\n" 91 | " tx wlan0 Reads data over stdin and sends it out over wlan0\n" 92 | "\n", MAX_USER_PACKET_LENGTH, MAX_USER_PACKET_LENGTH, FIFO_NAME); 93 | exit(1); 94 | } 95 | 96 | void set_port_no(uint8_t *pu, uint8_t port) { 97 | //dirty hack: the last byte of the mac address is the port number. this makes it easy to filter out specific ports via wireshark 98 | pu[sizeof(u8aRadiotapHeader) + SRC_MAC_LASTBYTE] = port; 99 | pu[sizeof(u8aRadiotapHeader) + DST_MAC_LASTBYTE] = port; 100 | } 101 | 102 | 103 | typedef struct { 104 | int seq_nr; 105 | int fd; 106 | int curr_pb; 107 | packet_buffer_t *pbl; 108 | } fifo_t; 109 | 110 | 111 | 112 | int packet_header_init(uint8_t *packet_header) { 113 | u8 *pu8 = packet_header; 114 | memcpy(packet_header, u8aRadiotapHeader, sizeof(u8aRadiotapHeader)); 115 | pu8 += sizeof(u8aRadiotapHeader); 116 | memcpy(pu8, u8aIeeeHeader, sizeof (u8aIeeeHeader)); 117 | pu8 += sizeof (u8aIeeeHeader); 118 | 119 | //determine the length of the header 120 | return pu8 - packet_header; 121 | } 122 | 123 | void fifo_init(fifo_t *fifo, int fifo_count, int block_size) { 124 | int i; 125 | 126 | for(i=0; i 1) { 145 | //new FIFO style 146 | 147 | //first, create all required fifos 148 | for(i=0; i *max_fifo_fd) { 188 | *max_fifo_fd = fifo[i].fd; 189 | } 190 | } 191 | } 192 | 193 | 194 | void pb_transmit_packet(pcap_t *ppcap, int seq_nr, uint8_t *packet_transmit_buffer, int packet_header_len, const uint8_t *packet_data, int packet_length) { 195 | //add header outside of FEC 196 | wifi_packet_header_t *wph = (wifi_packet_header_t*)(packet_transmit_buffer + packet_header_len); 197 | wph->sequence_number = seq_nr; 198 | 199 | //copy data 200 | memcpy(packet_transmit_buffer + packet_header_len + sizeof(wifi_packet_header_t), packet_data, packet_length); 201 | 202 | int plen = packet_length + packet_header_len + sizeof(wifi_packet_header_t); 203 | int r = pcap_inject(ppcap, packet_transmit_buffer, plen); 204 | if (r != plen) { 205 | pcap_perror(ppcap, "Trouble injecting packet"); 206 | exit(1); 207 | } 208 | } 209 | 210 | 211 | 212 | 213 | void pb_transmit_block(packet_buffer_t *pbl, pcap_t *ppcap, int *seq_nr, int port, int packet_length, uint8_t *packet_transmit_buffer, int packet_header_len, int data_packets_per_block, int fec_packets_per_block, int transmission_count) { 214 | int i; 215 | uint8_t *data_blocks[MAX_DATA_OR_FEC_PACKETS_PER_BLOCK]; 216 | uint8_t fec_pool[MAX_DATA_OR_FEC_PACKETS_PER_BLOCK][MAX_USER_PACKET_LENGTH]; 217 | uint8_t *fec_blocks[MAX_DATA_OR_FEC_PACKETS_PER_BLOCK]; 218 | 219 | 220 | for(i=0; i= argc) 352 | usage(); 353 | 354 | 355 | if(param_packet_length > MAX_USER_PACKET_LENGTH) { 356 | fprintf(stderr, "Packet length is limited to %d bytes (you requested %d bytes)\n", MAX_USER_PACKET_LENGTH, param_packet_length); 357 | return (1); 358 | } 359 | 360 | if(param_min_packet_length > param_packet_length) { 361 | fprintf(stderr, "Your minimum packet length is higher that your maximum packet length (%d > %d)\n", param_min_packet_length, param_packet_length); 362 | return (1); 363 | } 364 | 365 | if(param_fifo_count > MAX_FIFOS) { 366 | fprintf(stderr, "The maximum number of streams (FIFOS) is %d (you requested %d)\n", MAX_FIFOS, param_fifo_count); 367 | return (1); 368 | } 369 | 370 | if(param_data_packets_per_block > MAX_DATA_OR_FEC_PACKETS_PER_BLOCK || param_fec_packets_per_block > MAX_DATA_OR_FEC_PACKETS_PER_BLOCK) { 371 | fprintf(stderr, "Data and FEC packets per block are limited to %d (you requested %d data, %d FEC)\n", MAX_DATA_OR_FEC_PACKETS_PER_BLOCK, param_data_packets_per_block, param_fec_packets_per_block); 372 | return (1); 373 | } 374 | 375 | 376 | packet_header_length = packet_header_init(packet_transmit_buffer); 377 | fifo_init(fifo, param_fifo_count, param_data_packets_per_block); 378 | fifo_open(fifo, param_fifo_count); 379 | fifo_create_select_set(fifo, param_fifo_count, &fifo_set, &max_fifo_fd); 380 | 381 | 382 | //initialize forward error correction 383 | fec_init(); 384 | 385 | 386 | // open the interface in pcap 387 | szErrbuf[0] = '\0'; 388 | ppcap = pcap_open_live(argv[optind], 800, 1, 20, szErrbuf); 389 | if (ppcap == NULL) { 390 | fprintf(stderr, "Unable to open interface %s in pcap: %s\n", 391 | argv[optind], szErrbuf); 392 | return (1); 393 | } 394 | 395 | 396 | pcap_setnonblock(ppcap, 0, szErrbuf); 397 | 398 | 399 | 400 | 401 | start_time = time(NULL); 402 | while (!fBrokenSocket) { 403 | fd_set rdfs; 404 | int ret; 405 | 406 | 407 | rdfs = fifo_set; 408 | 409 | //wait for new data on the fifos 410 | ret = select(max_fifo_fd + 1, &rdfs, NULL, NULL, NULL); 411 | 412 | if(ret < 0) { 413 | perror("select"); 414 | return (1); 415 | } 416 | 417 | //cycle through all fifos and look for new data 418 | for(i=0; ilen == 0) { 429 | pb->len += sizeof(payload_header_t); //make space for a length field (will be filled later) 430 | } 431 | 432 | //read the data 433 | int inl = read(fifo[i].fd, pb->data + pb->len, param_packet_length - pb->len); 434 | if(inl < 0 || inl > param_packet_length-pb->len){ 435 | perror("reading stdin"); 436 | return 1; 437 | } 438 | 439 | if(inl == 0) { 440 | //EOF 441 | fprintf(stderr, "Warning: Lost connection to fifo %d. Please make sure that a data source is connected\n", i); 442 | usleep(1e5); 443 | continue; 444 | } 445 | 446 | pb->len += inl; 447 | 448 | //check if this packet is finished 449 | if(pb->len >= param_min_packet_length) { 450 | payload_header_t *ph = (payload_header_t*)pb->data; 451 | ph->data_length = pb->len - sizeof(payload_header_t); //write the length into the packet. this is needed since with fec we cannot use the wifi packet lentgh anymore. We could also set the user payload to a fixed size but this would introduce additional latency since tx would need to wait until that amount of data has been received 452 | pcnt++; 453 | 454 | //check if this block is finished 455 | if(fifo[i].curr_pb == param_data_packets_per_block-1) { 456 | pb_transmit_block(fifo[i].pbl, ppcap, &(fifo[i].seq_nr), i+param_port, param_packet_length, packet_transmit_buffer, packet_header_length, param_data_packets_per_block, param_fec_packets_per_block, param_transmission_count); 457 | fifo[i].curr_pb = 0; 458 | } 459 | else { 460 | fifo[i].curr_pb++; 461 | } 462 | 463 | } 464 | } 465 | 466 | 467 | if(pcnt % 128 == 0) { 468 | printf("%d data packets sent (interface rate: %.3f)\n", pcnt, 1.0 * pcnt / param_data_packets_per_block * (param_data_packets_per_block + param_fec_packets_per_block) / (time(NULL) - start_time)); 469 | } 470 | 471 | } 472 | 473 | 474 | printf("Broken socket\n"); 475 | 476 | return (0); 477 | } 478 | -------------------------------------------------------------------------------- /wifibroadcast.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #pragma once 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | typedef unsigned int u32; 20 | typedef unsigned short u16; 21 | typedef unsigned char u8; 22 | typedef u32 __le32; 23 | 24 | #if __BYTE_ORDER == __LITTLE_ENDIAN 25 | #define le16_to_cpu(x) (x) 26 | #define le32_to_cpu(x) (x) 27 | #else 28 | #define le16_to_cpu(x) ((((x)&0xff)<<8)|(((x)&0xff00)>>8)) 29 | #define le32_to_cpu(x) \ 30 | ((((x)&0xff)<<24)|(((x)&0xff00)<<8)|(((x)&0xff0000)>>8)|(((x)&0xff000000)>>24)) 31 | #endif 32 | #define unlikely(x) (x) 33 | 34 | #define MAX_PENUMBRA_INTERFACES 8 35 | 36 | --------------------------------------------------------------------------------