source: lib/protocols_l2.c @ a81d2fc

4.0.1-hotfixescachetimestampsdevelopdpdk-ndagetsilivegetfragoffhelplibtrace4ndag_formatpfringrc-4.0.1rc-4.0.2rc-4.0.3rc-4.0.4ringdecrementfixringperformanceringtimestampfixes
Last change on this file since a81d2fc was a81d2fc, checked in by Perry Lorier <perry@…>, 14 years ago

Split the protocol API's up into seperate files

  • Property mode set to 100644
File size: 9.0 KB
Line 
1/* Protocol decodes for layer 2 */
2#include "libtrace.h"
3#include "protocols.h"
4#include "libtrace_int.h"
5#include <assert.h>
6
7/* Returns the payload from 802.3 ethernet.  Type optionally returned in
8 * "type" in host byte order.  This will return a vlan header.
9 */
10void *trace_get_payload_from_ethernet(void *ethernet, 
11                uint16_t *type,
12                uint32_t *remaining)
13{
14        libtrace_ether_t *eth = (libtrace_ether_t*)ethernet;
15
16        if (remaining) {
17                if (*remaining < sizeof(*eth))
18                        return NULL;
19                *remaining-=sizeof(*eth);
20        }
21
22        if (type)
23                *type = ntohs(eth->ether_type);
24
25        return (void*)((char *)eth + sizeof(*eth));
26}
27
28/* skip any 802.1q headers if necessary
29 * type is input/output
30 */
31void *trace_get_vlan_payload_from_ethernet_payload(void *ethernet, uint16_t *type,
32                uint32_t *remaining)
33{
34        assert(type && "You must pass a type in!");
35
36        if (*type == 0x8100) {
37                libtrace_8021q_t *vlanhdr = (libtrace_8021q_t *)ethernet;
38
39                if (remaining) {
40                        if (*remaining < sizeof(libtrace_8021q_t))
41                                return NULL;
42
43                        *remaining=*remaining-sizeof(libtrace_8021q_t);
44                }
45
46                *type = ntohs(vlanhdr->vlan_ether_type);
47
48                return (void*)((char *)ethernet + sizeof(*vlanhdr));
49        }
50
51        return ethernet;
52}
53
54/* skip any MPLS headers if necessary, guessing what the next type is
55 * type is input/output.  If the next type is "ethernet" this will
56 * return a type of 0x0000.
57 */
58void *trace_get_mpls_payload_from_ethernet_payload(void *ethernet,
59                uint16_t *type, uint32_t *remaining)
60{
61        assert(type && "You must pass a type in!");
62
63        if (*type == 0x8847) {
64                if ((((char*)ethernet)[2]&0x01)==0) {
65                        *type = 0x8847;
66                }
67                else {
68                        if (!remaining || *remaining>=5) {
69                                switch (((char*)ethernet)[4]&0xF0) {
70                                        case 0x40:
71                                                *type = 0x0800;
72                                                break;
73                                        case 0x60:
74                                                *type = 0x86DD;
75                                                break;
76                                        default:
77                                                /* Ethernet */
78                                                *type = 0;
79                                }
80                        }
81                }
82                ethernet=(char*)ethernet+4;
83                if (remaining) {
84                        if (*remaining<4)
85                                return NULL;
86                        else
87                                *remaining-=4;
88                }
89
90
91                return ethernet;
92        }
93        else
94                return NULL;
95}
96
97static void *trace_get_payload_from_llcsnap(void *link,
98                uint16_t *type, uint32_t *remaining)
99{
100        /* 64 byte capture. */
101        libtrace_llcsnap_t *llc = (libtrace_llcsnap_t*)link;
102
103        if (remaining) {
104                if (*remaining < sizeof(libtrace_llcsnap_t))
105                        return NULL;
106                *remaining-=(sizeof(libtrace_llcsnap_t));
107        }
108
109        llc = (libtrace_llcsnap_t*)((char *)llc);
110
111        if (type) *type = ntohs(llc->type);
112
113        return (void*)((char*)llc+sizeof(*llc));
114}
115
116
117static void *trace_get_payload_from_80211(void *link, uint16_t *type, uint32_t *remaining)
118{
119        libtrace_80211_t *wifi;
120        uint16_t *eth; /* ethertype */
121        int8_t extra = 0; /* how many QoS bytes to skip */
122       
123        if (remaining && *remaining < sizeof(libtrace_80211_t))
124                return NULL;
125
126        wifi=(libtrace_80211_t*)link;
127
128        /* Data packet? */
129        if (wifi->type != 2) {
130                return NULL;
131        }
132
133        /* If FromDS and ToDS are both set then we have a four-address
134         * frame. Otherwise we have a three-address frame */
135        if (!(wifi->to_ds && wifi->from_ds)) 
136                extra -= 6; 
137       
138        /* Indicates QoS field present, see IEEE802.11e-2005 pg 21 */
139        if (wifi->subtype & 0x8) 
140                extra += 2;
141
142        if (remaining && *remaining < sizeof(*eth))
143                return NULL;
144
145        eth=(uint16_t *)((char*)wifi+sizeof(*wifi)+extra);
146       
147        if (*eth == 0xaaaa)
148                /* Payload contains an 802.2 LLC/SNAP frame */
149                return trace_get_payload_from_llcsnap((void *)eth, type, remaining);
150                       
151        /* Otherwise we assume an Ethernet II frame */
152        if (type) *type=ntohs(*eth);
153        if (remaining) *remaining = *remaining - sizeof(libtrace_80211_t) - extra - sizeof(*eth);
154       
155        return (void*)((char*)eth+sizeof(*eth));
156}
157
158static void *trace_get_payload_from_ppp(void *link, 
159                uint16_t *type, uint32_t *remaining)
160{
161        /* 64 byte capture. */
162        libtrace_ppp_t *ppp = (libtrace_ppp_t*)link;
163
164        if (remaining) {
165                if (*remaining < sizeof(libtrace_ppp_t))
166                        return NULL;
167                *remaining-=sizeof(libtrace_ppp_t);
168        }
169
170        if (type) {
171                switch(ntohs(ppp->protocol)) {
172                        case 0x0021: *type = 0x0800; break;
173                }
174        }
175
176
177        return (void*)((char *)ppp+sizeof(*ppp));
178}
179
180typedef struct libtrace_chdlc_t {
181        uint8_t address;        /** 0xF0 for unicast, 0xF8 for multicast */
182        uint8_t control;
183        uint16_t ethertype;
184} libtrace_chdlc_t;
185
186static void *trace_get_payload_from_chdlc(void *link, 
187                uint16_t *type, uint32_t *remaining)
188{
189        libtrace_chdlc_t *chdlc = (libtrace_chdlc_t*)link;
190
191        if (remaining) {
192                if (*remaining < sizeof(libtrace_chdlc_t))
193                        return NULL;
194                *remaining-=sizeof(libtrace_chdlc_t);
195        }
196
197        if (type) {
198                *type=ntohs(chdlc->ethertype);
199        }
200
201
202        return (void*)((char *)chdlc+sizeof(*chdlc));
203}
204
205void *trace_get_payload_from_link(void *link, libtrace_linktype_t linktype, 
206                uint16_t *type, uint32_t *remaining)
207{
208        void *l = NULL;
209        uint16_t dummytype;
210       
211        switch(linktype) {
212                case TRACE_TYPE_80211_PRISM:
213                        l = trace_get_payload_from_prism(link,&linktype,remaining);
214                        return (l ? trace_get_payload_from_link(l, TRACE_TYPE_80211, type, remaining) : NULL);
215                case TRACE_TYPE_80211_RADIO:
216                        l = trace_get_payload_from_radiotap(link,&linktype,remaining);
217                        return (l ? trace_get_payload_from_link(l, TRACE_TYPE_80211, type, remaining) : NULL);
218                case TRACE_TYPE_80211:
219                        return trace_get_payload_from_80211(link,type,remaining);
220
221                case TRACE_TYPE_ETH:
222                        return trace_get_payload_from_ethernet(link,type,remaining);
223                case TRACE_TYPE_NONE:
224                        if ((*(char*)link&0xF0) == 0x40)
225                                *type=0x0800;
226                        else if ((*(char*)link&0xF0) == 0x60)
227                                *type=0x86DD;
228                        return link; /* I love the simplicity */
229                case TRACE_TYPE_LINUX_SLL:
230                        l = trace_get_payload_from_linux_sll(link,&dummytype,remaining);
231                        if (type) *type = dummytype;
232                        return (l ? trace_get_payload_from_link(l,
233                                                arphrd_type_to_libtrace(dummytype), type, remaining) : NULL);
234                       
235                case TRACE_TYPE_PFLOG:
236                        return trace_get_payload_from_pflog(link,type,remaining);
237                case TRACE_TYPE_PPP:
238                        return trace_get_payload_from_ppp(link,type,remaining);
239                case TRACE_TYPE_ATM:
240                        l=trace_get_payload_from_atm(link,NULL,remaining);
241                        return (l ? trace_get_payload_from_llcsnap(l,
242                                                type, remaining):NULL);
243                case TRACE_TYPE_DUCK:
244                        return NULL; /* duck packets have no payload! */
245                case TRACE_TYPE_METADATA:
246                        return NULL; /* The payload is in these packets does
247                                        not correspond to a genuine link-layer
248                                        */
249                default:
250                        break;
251        }
252        fprintf(stderr, "Don't understand link layer type %i in trace_get_payload_from_link()\n",
253                linktype);
254        return NULL;
255}
256
257DLLEXPORT void *trace_get_layer2(const libtrace_packet_t *packet,
258                libtrace_linktype_t *linktype,
259                uint32_t *remaining) 
260{
261        uint32_t dummyrem;
262       
263        assert(packet != NULL);
264        assert(linktype != NULL);
265
266        if (remaining == NULL)
267                remaining = &dummyrem;
268       
269        void *meta = trace_get_packet_meta(packet, linktype, remaining);
270
271        /* If there are no meta-data headers, we just return the start of the
272         * packet buffer, along with the linktype, etc.
273         */
274        if (meta == NULL) 
275                return trace_get_packet_buffer(packet, linktype, remaining);
276       
277        /* If there are meta-data headers, we need to skip over them until we
278         * find a non-meta data header and return that.
279         */
280        for(;;) {
281                void *nexthdr = trace_get_payload_from_meta(meta, 
282                                linktype, remaining);
283                if (nexthdr == NULL)
284                        return meta;
285                meta = nexthdr;
286        }
287}
288
289DLLEXPORT
290void *trace_get_payload_from_atm(void *link,
291                uint8_t *type, uint32_t *remaining)
292{
293        libtrace_atm_capture_cell_t *cell;
294        if (remaining && *remaining<sizeof(libtrace_atm_capture_cell_t))
295                return NULL;
296        cell=(libtrace_atm_capture_cell_t*)link;
297
298        if (type)
299                *type=cell->pt;
300
301        if (remaining)
302                *remaining-=sizeof(libtrace_atm_capture_cell_t);
303
304        return ((char*)link)+sizeof(libtrace_atm_capture_cell_t);
305}
306
307
308
309DLLEXPORT void *trace_get_payload_from_layer2(void *link,
310                libtrace_linktype_t linktype,
311                uint16_t *ethertype,
312                uint32_t *remaining)
313{
314        void *l;
315        switch(linktype) {
316                /* Packet Metadata headers, not layer2 headers */
317                case TRACE_TYPE_80211_PRISM:
318                case TRACE_TYPE_80211_RADIO:
319                case TRACE_TYPE_LINUX_SLL:
320                        return NULL;
321
322                /* duck packets have no payload! */
323                case TRACE_TYPE_DUCK:
324                        return NULL;
325
326                /* The payload is in these packets does
327                   not correspond to a genuine link-layer
328                   */
329                case TRACE_TYPE_METADATA:
330                        return NULL;
331
332                case TRACE_TYPE_80211:
333                        return trace_get_payload_from_80211(link,ethertype,remaining);
334                case TRACE_TYPE_ETH:
335                        return trace_get_payload_from_ethernet(link,ethertype,remaining);
336                case TRACE_TYPE_NONE:
337                        if ((*(char*)link&0xF0) == 0x40)
338                                *ethertype=0x0800;
339                        else if ((*(char*)link&0xF0) == 0x60)
340                                *ethertype=0x86DD;
341                        return link; /* I love the simplicity */
342                case TRACE_TYPE_PFLOG:
343                        return trace_get_payload_from_pflog(link,ethertype,remaining);
344                case TRACE_TYPE_PPP:
345                        return trace_get_payload_from_ppp(link,ethertype,remaining);
346                case TRACE_TYPE_ATM:
347                        l=trace_get_payload_from_atm(link,NULL,remaining);
348                        /* FIXME: We shouldn't skip llcsnap here, we should return
349                         * an ethertype for it (somehow)
350                         */
351                        return (l ? trace_get_payload_from_llcsnap(l,
352                                                ethertype, remaining):NULL);
353                case TRACE_TYPE_LLCSNAP:
354                        return trace_get_payload_from_llcsnap(link,ethertype,remaining);
355
356                case TRACE_TYPE_HDLC_POS:
357                        return trace_get_payload_from_chdlc(link,ethertype,
358                                        remaining);
359                /* TODO: Unsupported */
360                case TRACE_TYPE_POS:
361                case TRACE_TYPE_AAL5:
362                        return NULL;
363        }
364        return NULL;
365
366}
367
368
369
Note: See TracBrowser for help on using the repository browser.