source: lib/link_wireless.c @ 17a3dff

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since 17a3dff was 9cc1266, checked in by Shane Alcock <salcock@…>, 10 years ago
  • Fixed poor performance of the event API by greatly reducing the amount of packets created, copied and freed
  • We now cache the transport header and payload length for each packet
  • We now deal with Linux SLL Ethernet captures taken using tcpdump with -i any correctly.
  • Changed parameters for internal function trace_get_payload_from_sll - it now sets both the arphrd type and the next protocol
  • Moved ARPHRD definitions into a separate header file, as they come in handy anywhere we deal with SLL headers
  • Property mode set to 100644
File size: 16.5 KB
Line 
1/*
2 * This file is part of libtrace
3 *
4 * Copyright (c) 2007,2008,2009,2010 The University of Waikato, Hamilton,
5 * New Zealand.
6 *
7 * Authors: Scott Raynel
8 *          Perry Lorier
9 *         
10 * All rights reserved.
11 *
12 * This code has been developed by the University of Waikato WAND
13 * research group. For further information please see http://www.wand.net.nz/
14 *
15 * libtrace is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
19 *
20 * libtrace is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with libtrace; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28 *
29 * $Id$
30 *
31 */
32
33#include "libtrace_int.h"
34#include "libtrace.h"
35
36/* The file contains all the functions necessary to access various measurement
37 * values that are specific to wireless MACs ( RadioTap in particular ).
38 *
39 * Credit for all this code goes to Scott Raynel.
40 */
41
42/* Used for Radiotap fields which must be naturally aligned */
43#define ALIGN_NATURAL_64(_p,_s) \
44        while ( (_p - _s) % sizeof(uint64_t)) _p++
45#define ALIGN_NATURAL_32(_p,_s) \
46        while ( (_p - _s) % sizeof(uint32_t)) _p++
47#define ALIGN_NATURAL_16(_p,_s) \
48        while ( (_p - _s) % sizeof(uint16_t)) _p++
49
50/** Gets a field from a Radiotap header.
51 * @param link the radiotap header
52 * @param field the radiotap field we want to access
53 * @return a void pointer to the field. It is up to the caller to cast to the
54 * appropriate type.
55 * @note Radiotap fields are always little-endian
56 */
57static void *trace_get_radiotap_field(void *link, libtrace_radiotap_field_t field)
58{
59        struct libtrace_radiotap_t *rtap = (struct libtrace_radiotap_t *)link;
60        uint8_t *p;
61        uint8_t *s;
62
63        /* Check if the field exists in the radiotap header before proceeding
64        */
65        if ((bswap_le_to_host32(rtap->it_present) & (1 << field)) == 0) return NULL;
66
67        /* Skip over any extended bitmasks */
68        p = (uint8_t *) &(rtap->it_present);
69
70        while ( bswap_le_to_host32(*((uint32_t*)p)) & (1U << TRACE_RADIOTAP_EXT) ) {
71                p += sizeof (uint32_t);
72        }
73
74        /* Point p at the first field of radiotap data and remember it for later
75         * when we're doing field alignment
76         */
77        p += sizeof(uint32_t);
78        s = p;
79
80        if (field == TRACE_RADIOTAP_TSFT) 
81                /* Always aligned */
82                return (void*)p;
83        if (bswap_le_to_host32(rtap->it_present) & (1 << TRACE_RADIOTAP_TSFT))
84                p += sizeof (uint64_t);
85
86        if (field == TRACE_RADIOTAP_FLAGS)
87                /* Always aligned */
88                return (void*)p;
89        if (bswap_le_to_host32(rtap->it_present) & (1 << TRACE_RADIOTAP_FLAGS))
90                p += sizeof (uint8_t);
91
92        if (field == TRACE_RADIOTAP_RATE)
93                /* Always aligned */
94                return (void*)p;
95        if (bswap_le_to_host32(rtap->it_present) & (1 << TRACE_RADIOTAP_RATE))
96                p+= sizeof (uint8_t);
97
98        if (field == TRACE_RADIOTAP_CHANNEL)
99        {
100                ALIGN_NATURAL_16(p,s);
101                return (void *)p;
102        }
103        if (bswap_le_to_host32(rtap->it_present) & (1 << TRACE_RADIOTAP_CHANNEL))
104                p+= sizeof (uint32_t);
105
106        if (field == TRACE_RADIOTAP_FHSS)
107        {
108                ALIGN_NATURAL_16(p,s);
109                return (void *)p;
110        }
111        if (bswap_le_to_host32(rtap->it_present) & (1 << TRACE_RADIOTAP_FHSS))
112                p+= sizeof (uint16_t);
113
114        if (field == TRACE_RADIOTAP_DBM_ANTSIGNAL)
115                return (void *)p;
116        if (bswap_le_to_host32(rtap->it_present) & (1 << TRACE_RADIOTAP_DBM_ANTSIGNAL))
117                p+= sizeof (uint8_t);
118
119        if (field == TRACE_RADIOTAP_DBM_ANTNOISE)
120                return (void *)p;
121        if (bswap_le_to_host32(rtap->it_present) & (1 << TRACE_RADIOTAP_DBM_ANTNOISE))
122                p+= sizeof (uint8_t);
123
124        if (field == TRACE_RADIOTAP_LOCK_QUALITY)
125        {
126                ALIGN_NATURAL_16(p,s);
127                return (void *)p;
128        }
129        if (bswap_le_to_host32(rtap->it_present) & (1 << TRACE_RADIOTAP_LOCK_QUALITY))
130                p+= sizeof (uint16_t);
131
132        if (field == TRACE_RADIOTAP_TX_ATTENUATION)
133        {
134                ALIGN_NATURAL_16(p,s);
135                return (void *)p;
136        }
137        if (bswap_le_to_host32(rtap->it_present) & (1 << TRACE_RADIOTAP_TX_ATTENUATION))
138                p+= sizeof (uint16_t);
139
140        if (field == TRACE_RADIOTAP_DB_TX_ATTENUATION)
141        {
142                ALIGN_NATURAL_16(p,s);
143                return (void *)p;
144        }
145        if (bswap_le_to_host32(rtap->it_present) & (1 << TRACE_RADIOTAP_DB_TX_ATTENUATION))
146                p+= sizeof (uint16_t);
147
148        if (field == TRACE_RADIOTAP_DBM_TX_POWER)
149                return (void *)p;
150        if (bswap_le_to_host32(rtap->it_present) & (1 << TRACE_RADIOTAP_DBM_TX_POWER))
151                p+= sizeof (uint8_t);
152
153        if (field == TRACE_RADIOTAP_ANTENNA)
154                return (void *)p;
155        if (bswap_le_to_host32(rtap->it_present) & (1 << TRACE_RADIOTAP_ANTENNA))
156                p+= sizeof (uint8_t);
157
158        if (field == TRACE_RADIOTAP_DB_ANTSIGNAL)
159                return (void *)p;
160        if (bswap_le_to_host32(rtap->it_present) & (1 << TRACE_RADIOTAP_DB_ANTSIGNAL))
161                p+= sizeof (uint8_t);
162
163        if (field == TRACE_RADIOTAP_DB_ANTNOISE)
164                return (void *) p;
165        /*
166        if (bswap_le_to_host32(rtap->it_present) & (1 << TRACE_RADIOTAP_DB_ANTNOISE))
167                p+= sizeof (uint8_t);
168        */
169
170        /* Unknown field */
171        return NULL;
172} 
173
174DLLEXPORT bool trace_get_wireless_tsft(void *link, 
175                libtrace_linktype_t linktype, uint64_t *tsft)
176{
177        uint64_t *p;
178        void *l;
179        uint16_t type;
180        if (link == NULL || tsft == NULL) return false;
181
182        switch (linktype) {
183                case TRACE_TYPE_80211_RADIO:
184                        if( (p = (uint64_t *) trace_get_radiotap_field(link, 
185                                                        TRACE_RADIOTAP_TSFT))) {
186                                *tsft = bswap_le_to_host64(*p);
187                                return true;
188                        } else break;
189                case TRACE_TYPE_LINUX_SLL:
190                        l = trace_get_payload_from_linux_sll(link, &type, NULL, NULL );
191                        return trace_get_wireless_tsft(l, arphrd_type_to_libtrace(type), tsft);
192
193                case TRACE_TYPE_80211_PRISM:
194                        return false;
195                default:
196                        return false;
197        }
198        return false;
199}
200
201/*
202 * This function isn't portable across drivers, so has been left static
203 * for now. Maybe it will be included in the API later if it becomes useful
204 * and we come up with a suitable abstraction.
205 * This function isn't marked static as the various format modules need to
206 * access it for get_wire_length(). It's not meant to be exported though.
207 */
208bool trace_get_wireless_flags(void *link, 
209                libtrace_linktype_t linktype, uint8_t *flags)
210{
211        uint8_t *p;
212        void *l;
213        uint16_t type;
214
215        if (link == NULL || flags == NULL) return false;
216
217        switch(linktype) {
218                case TRACE_TYPE_80211_RADIO:
219                        if (( p = (uint8_t *) trace_get_radiotap_field(link,
220                                                        TRACE_RADIOTAP_FLAGS))) {
221                                *flags = *p;
222                                return true;
223                        } else break;
224                case TRACE_TYPE_LINUX_SLL:
225                        l = trace_get_payload_from_linux_sll(link, &type, NULL, NULL);
226                        return trace_get_wireless_flags(l, arphrd_type_to_libtrace(type), flags);
227                default:
228                        return false;
229        }
230        return false;
231}
232
233DLLEXPORT bool trace_get_wireless_rate(void *link, 
234                libtrace_linktype_t linktype, uint8_t *rate)
235{
236        uint8_t * p;
237        void *l;
238        uint16_t type;
239
240        if (link == NULL || rate == NULL) return false ;
241        switch (linktype) {
242                case TRACE_TYPE_80211_RADIO:
243                        if ( (p = (uint8_t *) trace_get_radiotap_field(link,
244                                                        TRACE_RADIOTAP_RATE))) {
245                                *rate = *p;
246                                return true;
247                        } else break;
248                case TRACE_TYPE_LINUX_SLL:
249                        l = trace_get_payload_from_linux_sll(link, &type, NULL, NULL);
250                        return trace_get_wireless_rate(l, arphrd_type_to_libtrace(type), rate);
251                default:
252                        return false;
253        }
254        return false;
255}
256
257DLLEXPORT bool trace_get_wireless_freq(void *link, 
258                libtrace_linktype_t linktype, uint16_t *freq)
259{
260        uint16_t *p;
261        void *l;
262        uint16_t type;
263
264        if (link == NULL || freq == NULL) return false;
265        switch (linktype) {
266                case TRACE_TYPE_80211_RADIO:
267                        /* NB: The channel field is actually two 16 bit fields.
268                         * The chan_freq field is the first of those two, so we
269                         * just cast it to a uint16_t.
270                         */
271                        if (( p = (uint16_t *) trace_get_radiotap_field(link,
272                                                        TRACE_RADIOTAP_CHANNEL))) {
273                                *freq = bswap_le_to_host16(*p);
274                                return true;
275                        } else break;
276                case TRACE_TYPE_LINUX_SLL:
277                        l = trace_get_payload_from_linux_sll(link, &type, NULL, NULL);
278                        return trace_get_wireless_freq(l, arphrd_type_to_libtrace(type), freq);
279                default:
280                        return false;
281        }
282        return false;
283}
284
285#if 0
286
287/*
288 * This function isn't portable across drivers, so has been left static
289 * for now. Maybe it will be included in the API later if it becomes useful
290 * and we come up with a suitable abstraction.
291 */
292static
293bool trace_get_wireless_channel_flags(void *link,
294                libtrace_linktype_t linktype, uint16_t *flags)
295{
296        uint16_t *p;
297        void *l;
298        uint16_t type;
299        if (link == NULL || flags == NULL) return false;
300        switch (linktype) {
301                case TRACE_TYPE_80211_RADIO:
302                        /* NB: The channel field is actually two 16 bit fields.
303                         * The chan_flags field is the second of the two, so we need
304                         * to take the pointer returned by getting the channel field
305                         * and increment it.
306                         */
307                        if ((p = (uint16_t *) trace_get_radiotap_field(link,
308                                                        TRACE_RADIOTAP_CHANNEL))) {
309                                *flags = bswap_le_to_host16(*(++p));
310                                return true;
311                        } else break;
312                case TRACE_TYPE_LINUX_SLL:
313                        l = trace_get_payload_from_linux_sll(link, &type, NULL, NULL);
314                        return trace_get_wireless_channel_flags(l, arphrd_type_to_libtrace(type), flags);
315                default:
316                        return false;
317        }
318        return false;
319}
320
321/* Not sure that this function is useful for now - who uses FHSS?
322 * This might get exported in the future if it becomes useful
323 */
324static
325bool trace_get_wireless_fhss_hopset(void *link,
326                libtrace_linktype_t linktype, uint8_t *hopset)
327{
328        uint8_t *p;
329        void *l;
330        uint16_t type;
331
332        if (link == NULL || hopset == NULL) return false;
333        switch(linktype) {
334                case TRACE_TYPE_80211_RADIO:
335                        /* NB: As above with the channel field, the fhss field is
336                         * similar.
337                         */
338                        if( (p = (uint8_t *) trace_get_radiotap_field(link,
339                                                        TRACE_RADIOTAP_FHSS))) {
340                                *hopset = *p;
341                                return true;
342                        } else break;
343                case TRACE_TYPE_LINUX_SLL:
344                        l = trace_get_payload_from_linux_sll(link, &type, NULL, NULL);
345                        return trace_get_wireless_fhss_hopset(l, arphrd_type_to_libtrace(type), hopset);
346                default:
347                        return false;
348        }
349        return false;
350}
351
352/* Not sure that this function is useful for now - who uses FHSS?
353 * This might get exported in the future if it becomes useful
354 */
355static
356bool trace_get_wireless_fhss_hoppattern(void *link,
357                libtrace_linktype_t linktype, uint8_t *hoppattern)
358{
359        uint8_t *p;
360        void *l;
361        uint16_t type;
362        if (link == NULL || hoppattern == NULL) return false;
363        switch (linktype) {
364                case TRACE_TYPE_80211_RADIO:
365                        if((p = (uint8_t *) trace_get_radiotap_field(link,
366                                                        TRACE_RADIOTAP_FHSS))) {
367                                *hoppattern = *(++p);
368                                return true;
369                        } else break;
370                case TRACE_TYPE_LINUX_SLL:
371                        l = trace_get_payload_from_linux_sll(link, &type, NULL, NULL);
372                        return trace_get_wireless_fhss_hoppattern(l, arphrd_type_to_libtrace(type), hoppattern);
373                default:
374                        return false;
375        }
376        return false;
377}
378
379#endif
380
381DLLEXPORT bool trace_get_wireless_signal_strength_dbm(void *link,
382                libtrace_linktype_t linktype, int8_t *strength)
383{
384        int8_t *p;
385        void *l;
386        uint16_t type;
387
388        if (link == NULL || strength == NULL) return false;
389        switch(linktype) {
390                case TRACE_TYPE_80211_RADIO:
391                        if ((p =  (int8_t *) trace_get_radiotap_field(link,
392                                                        TRACE_RADIOTAP_DBM_ANTSIGNAL))) {
393                                *strength = *p;
394                                return true;
395                        } else break;
396                case TRACE_TYPE_LINUX_SLL:
397                        l = trace_get_payload_from_linux_sll(link, &type, NULL, NULL);
398                        return trace_get_wireless_signal_strength_dbm(l, arphrd_type_to_libtrace(type), strength);
399                default:
400                        return false;
401        }
402        return false;
403}
404
405DLLEXPORT bool trace_get_wireless_noise_strength_dbm(void *link,
406                libtrace_linktype_t linktype, int8_t *strength)
407{
408        uint8_t *p;
409        void *l;
410        uint16_t type;
411
412        if (link == NULL || strength == NULL) return false;
413        switch (linktype) {
414                case TRACE_TYPE_80211_RADIO:
415                        if (( p = (uint8_t *) trace_get_radiotap_field(link,
416                                        TRACE_RADIOTAP_DBM_ANTNOISE))) {
417                                *strength = *p;
418                                return true;
419                        } else break;
420                case TRACE_TYPE_LINUX_SLL:
421                        l = trace_get_payload_from_linux_sll(link, &type, NULL, NULL);
422                        return trace_get_wireless_noise_strength_dbm(l, arphrd_type_to_libtrace(type), strength);
423                default:
424                        return false;
425        }
426        return false;
427}
428
429DLLEXPORT bool trace_get_wireless_signal_strength_db(void *link,
430                libtrace_linktype_t linktype, uint8_t *strength)
431{
432        uint8_t *p;
433        void *l;
434        uint16_t type;
435
436        if (link == NULL || strength == NULL) return false;
437        switch (linktype) {
438                case TRACE_TYPE_80211_RADIO:
439                        if ((p =  (uint8_t *) trace_get_radiotap_field(link,
440                                                        TRACE_RADIOTAP_DB_ANTSIGNAL))) {
441                                *strength = *p;
442                                return true;
443                        } else break;
444                case TRACE_TYPE_LINUX_SLL:
445                        l = trace_get_payload_from_linux_sll(link, &type, NULL, NULL);
446                        return trace_get_wireless_signal_strength_db(l, arphrd_type_to_libtrace(type), strength);
447                default:
448                        return false;
449        }
450        return false ;
451}
452
453DLLEXPORT bool trace_get_wireless_noise_strength_db(void *link,
454                libtrace_linktype_t linktype, uint8_t *strength)
455{
456        uint8_t *p;
457        void *l;
458        uint16_t type;
459
460        if (link == NULL || strength == NULL) return false;
461        switch (linktype) {
462                case TRACE_TYPE_80211_RADIO:
463                        if ((p = (uint8_t *) trace_get_radiotap_field(link,
464                                                        TRACE_RADIOTAP_DB_ANTNOISE))) {
465                                *strength = *p;
466                                return true;
467                        } else break;
468                case TRACE_TYPE_LINUX_SLL:
469                        l = trace_get_payload_from_linux_sll(link, &type, NULL, NULL);
470                        return trace_get_wireless_noise_strength_db(l, arphrd_type_to_libtrace(type), strength);
471                default:
472                        return false;
473        }
474        return false;
475}
476
477#if 0
478/* Not sure if this function is useful. As the radiotap documentation says,
479 * there's no set metric for defining the quality of the Barker Code Lock.
480 * Maybe it will be exported later if it becomes useful.
481 */
482static
483bool trace_get_wireless_lock_quality(void *link,
484                libtrace_linktype_t linktype, uint16_t *quality)
485{
486        uint16_t *p;
487        void *l;
488        uint16_t type;
489
490        if (link == NULL || quality == NULL) return false;
491        switch (linktype) {
492                case TRACE_TYPE_80211_RADIO:
493                        if((p = (uint16_t *) trace_get_radiotap_field(link,
494                                                        TRACE_RADIOTAP_LOCK_QUALITY))) {
495                                *quality = bswap_le_to_host16(*p);
496                                return true;
497                        } else break;
498                case TRACE_TYPE_LINUX_SLL:
499                        l = trace_get_payload_from_linux_sll(link, &type, NULL, NULL);
500                        return trace_get_wireless_lock_quality(l, arphrd_type_to_libtrace(type), quality);
501                default:
502                        return false;
503        }
504        return false;
505}
506
507#endif
508
509DLLEXPORT bool trace_get_wireless_tx_attenuation(void *link,
510                libtrace_linktype_t linktype, uint16_t *attenuation)
511{
512        uint16_t *p;
513        void *l;
514        uint16_t type;
515
516        if (link == NULL || attenuation == 0) return false;
517        switch (linktype) {
518                case TRACE_TYPE_80211_RADIO:
519                        if ((p = (uint16_t *) trace_get_radiotap_field(link,
520                                                        TRACE_RADIOTAP_TX_ATTENUATION))) {
521                                *attenuation = bswap_le_to_host16(*p);
522                                return true;
523                        } else break;
524                case TRACE_TYPE_LINUX_SLL:
525                        l = trace_get_payload_from_linux_sll(link, &type, NULL, NULL);
526                        return trace_get_wireless_tx_attenuation(l, arphrd_type_to_libtrace(type), attenuation);
527                default:
528                        return false;
529        }
530        return false;
531}
532
533DLLEXPORT bool trace_get_wireless_tx_attenuation_db(void *link,
534                libtrace_linktype_t linktype, uint16_t *attenuation)
535{
536        uint16_t *p;
537        void *l;
538        uint16_t type;
539
540        if (link == NULL || attenuation == NULL) return false;
541        switch (linktype) {
542                case TRACE_TYPE_80211_RADIO:
543                        if ((p = (uint16_t *) trace_get_radiotap_field(link,
544                                                        TRACE_RADIOTAP_DB_TX_ATTENUATION))) {
545                                *attenuation = bswap_le_to_host16(*p);
546                                return true;
547                        } else break;
548                case TRACE_TYPE_LINUX_SLL:
549                        l = trace_get_payload_from_linux_sll(link, &type, NULL, NULL);
550                        return trace_get_wireless_tx_attenuation_db(l, arphrd_type_to_libtrace(type), attenuation);
551                default:
552                        return false;
553        }
554        return false;
555}
556
557DLLEXPORT bool trace_get_wireless_tx_power_dbm(void *link,
558                libtrace_linktype_t linktype, int8_t *txpower)
559{
560        int8_t *p;
561        void *l;
562        uint16_t type;
563
564        if (link == NULL || txpower == NULL) return false;
565        switch (linktype) {
566                case TRACE_TYPE_80211_RADIO:
567                        if ((p=(int8_t *) trace_get_radiotap_field(link,
568                                                        TRACE_RADIOTAP_DBM_TX_POWER))) {
569                                *txpower = *p;
570                                return true;
571                        } else break;
572                case TRACE_TYPE_LINUX_SLL:
573                        l = trace_get_payload_from_linux_sll(link, &type, NULL, NULL);
574                        return trace_get_wireless_tx_power_dbm(l, arphrd_type_to_libtrace(type), txpower);
575                default:
576                        return false;
577        }
578        return false;
579}
580
581
582DLLEXPORT bool trace_get_wireless_antenna(void *link,
583                libtrace_linktype_t linktype, uint8_t *antenna)
584{
585        uint8_t *p;
586        void *l;
587        uint16_t type;
588
589        if (link == NULL || antenna == NULL) return false;
590        switch (linktype) {
591                case TRACE_TYPE_80211_RADIO:
592                        if ((p = (uint8_t *) trace_get_radiotap_field(link,
593                                                        TRACE_RADIOTAP_ANTENNA))) {
594                                *antenna = *p;
595                                return true;
596                        } else break;
597                case TRACE_TYPE_LINUX_SLL:
598                        l = trace_get_payload_from_linux_sll(link, &type, NULL, NULL);
599                        return trace_get_wireless_antenna(l, arphrd_type_to_libtrace(type), antenna);
600                default:
601                        return false;
602        }
603        return false;
604}
605
Note: See TracBrowser for help on using the repository browser.