source: lib/linktypes.c @ 4697684

cachetimestampsdevelopdpdk-ndagetsiliverc-4.0.3rc-4.0.4ringdecrementfixringperformance
Last change on this file since 4697684 was 4697684, checked in by Shane Alcock <salcock@…>, 3 years ago

Add support for ARPHRD_IPGRE

Captures from GRE tunnel interfaces should now work correctly.

  • Property mode set to 100644
File size: 12.6 KB
Line 
1/*
2 *
3 * Copyright (c) 2007-2016 The University of Waikato, Hamilton, New Zealand.
4 * All rights reserved.
5 *
6 * This file is part of libtrace.
7 *
8 * This code has been developed by the University of Waikato WAND
9 * research group. For further information please see http://www.wand.net.nz/
10 *
11 * libtrace is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * libtrace is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 *
24 *
25 */
26#include "config.h"
27#include "libtrace.h"
28
29#include "rt_protocol.h"
30#include <assert.h>
31#include "libtrace_int.h"
32#include <stdlib.h>
33#include <string.h>
34
35#include "libtrace_arphrd.h"
36
37
38/* This file maps libtrace types to/from pcap DLT and erf types
39 *
40 * When adding a new linktype to libtrace, add the mapping(s) here,
41 * and add the understanding of the type to get_ip(), and perhaps
42 * get_{source,destination}_mac (if your linklayer has mac's)
43 */
44
45libtrace_linktype_t pcap_linktype_to_libtrace(libtrace_dlt_t linktype)
46{
47        switch(linktype) {
48                case TRACE_DLT_RAW:
49                case TRACE_DLT_LINKTYPE_RAW: return TRACE_TYPE_NONE;
50                case TRACE_DLT_EN10MB: return TRACE_TYPE_ETH;
51                case TRACE_DLT_IEEE802_11: return TRACE_TYPE_80211;
52                case TRACE_DLT_LINUX_SLL: return TRACE_TYPE_LINUX_SLL;
53                case TRACE_DLT_PFLOG: return TRACE_TYPE_PFLOG;
54                case TRACE_DLT_IEEE802_11_RADIO: return TRACE_TYPE_80211_RADIO;
55                case TRACE_DLT_ATM_RFC1483: return TRACE_TYPE_LLCSNAP;
56                case TRACE_DLT_PPP: return TRACE_TYPE_PPP;
57                case TRACE_DLT_PPP_SERIAL: return TRACE_TYPE_POS;
58                case TRACE_DLT_C_HDLC: return TRACE_TYPE_HDLC_POS;
59                case TRACE_DLT_OPENBSD_LOOP: return TRACE_TYPE_OPENBSD_LOOP;
60                /* Unhandled */
61                case TRACE_DLT_ERROR:
62                case TRACE_DLT_NULL:    /* Raw IP frame with a BSD specific
63                                         * header If you want raw L3 headers
64                                         * use TRACE_DLT_RAW
65                                         */
66                        break;
67        }
68        return TRACE_TYPE_UNKNOWN;
69}
70
71libtrace_dlt_t libtrace_to_pcap_dlt(libtrace_linktype_t type)
72{
73        /* If pcap doesn't have a DLT, you can either ask pcap to register
74         * you a DLT, (and perhaps write a tcpdump decoder for it), or you
75         * can add it to demote_packet
76         */
77        switch(type) {
78                case TRACE_TYPE_NONE: return TRACE_DLT_RAW; 
79                case TRACE_TYPE_ETH: return TRACE_DLT_EN10MB;
80                case TRACE_TYPE_80211: return TRACE_DLT_IEEE802_11;
81                case TRACE_TYPE_LINUX_SLL: return TRACE_DLT_LINUX_SLL;
82                case TRACE_TYPE_PFLOG: return TRACE_DLT_PFLOG;
83                case TRACE_TYPE_80211_RADIO: return TRACE_DLT_IEEE802_11_RADIO;
84                case TRACE_TYPE_LLCSNAP: return TRACE_DLT_ATM_RFC1483;
85                case TRACE_TYPE_PPP:    return TRACE_DLT_PPP;
86                case TRACE_TYPE_HDLC_POS: return TRACE_DLT_C_HDLC;
87                /* Theres more than one type of PPP.  Who knew? */
88                case TRACE_TYPE_POS:    return TRACE_DLT_PPP_SERIAL; 
89                case TRACE_TYPE_OPENBSD_LOOP: return TRACE_DLT_OPENBSD_LOOP;
90
91                /* Below here are unsupported conversions */
92                /* Despite hints to the contrary, there is no DLT
93                 * for 'raw atm packets that happen to be missing
94                 * the HEC' or even 'raw atm packets that have a hec'.
95                 *
96                 * The closest are DLT_ATM_RFC1483 but that doesn't
97                 * include the ATM header, only the LLCSNAP header.
98                 */
99                case TRACE_TYPE_ATM:
100                /* pcap has no DLT for DUCK */
101                case TRACE_TYPE_DUCK:
102                /* Used for test traces within WAND */
103                case TRACE_TYPE_80211_PRISM:   
104                /* Probably == PPP */
105                /* TODO: We haven't researched these yet */
106                case TRACE_TYPE_AAL5:
107                case TRACE_TYPE_METADATA:
108                case TRACE_TYPE_NONDATA:
109                        break;
110                case TRACE_TYPE_UNKNOWN:
111                        break;
112        }
113        return TRACE_DLT_ERROR;
114}
115
116static libtrace_dlt_t pcap_dlt_to_pcap_linktype(libtrace_dlt_t linktype)
117{
118        switch (linktype) {
119                case TRACE_DLT_RAW: return TRACE_DLT_LINKTYPE_RAW;
120                default:
121                                    return linktype;
122        }
123}
124
125libtrace_dlt_t libtrace_to_pcap_linktype(libtrace_linktype_t type)
126{
127        return pcap_dlt_to_pcap_linktype(libtrace_to_pcap_dlt(type));
128}
129
130libtrace_rt_types_t pcap_linktype_to_rt(libtrace_dlt_t linktype) 
131{
132        /* For pcap the rt type is just the linktype + a fixed value */
133        return pcap_dlt_to_pcap_linktype(linktype) + TRACE_RT_DATA_DLT;
134}
135
136libtrace_rt_types_t bpf_linktype_to_rt(libtrace_dlt_t linktype) {
137        return pcap_dlt_to_pcap_linktype(linktype) + TRACE_RT_DATA_BPF;
138
139}
140
141libtrace_rt_types_t pcapng_linktype_to_rt(libtrace_dlt_t linktype) {
142
143        return TRACE_RT_DATA_PCAPNG + pcap_dlt_to_pcap_linktype(linktype);
144}
145
146libtrace_dlt_t rt_to_pcap_linktype(libtrace_rt_types_t rt_type)
147{
148
149        if (rt_type >= TRACE_RT_DATA_DLT && rt_type < TRACE_RT_DATA_DLT_END) {
150                /* RT type is in the pcap range */
151                return rt_type - TRACE_RT_DATA_DLT;
152        }
153        else if (rt_type >= TRACE_RT_DATA_BPF && rt_type < TRACE_RT_DATA_BPF_END) {
154                return rt_type - TRACE_RT_DATA_BPF;
155        } else if (rt_type >= TRACE_RT_DATA_PCAPNG && rt_type < TRACE_RT_DATA_PCAPNG_END) {
156                return rt_type - TRACE_RT_DATA_PCAPNG;
157        }
158
159        fprintf(stderr, "Error: RT type %u cannot be converted to a pcap DLT\n", rt_type);
160        assert(false);
161        return 0;       /* satisfy warnings */
162}
163
164libtrace_linktype_t erf_type_to_libtrace(uint8_t erf)
165{
166        switch (erf) {
167                case TYPE_HDLC_POS:     return TRACE_TYPE_HDLC_POS;
168                case TYPE_ETH:          return TRACE_TYPE_ETH;
169                case TYPE_ATM:          return TRACE_TYPE_ATM;
170                case TYPE_AAL5:         return TRACE_TYPE_AAL5;
171                case TYPE_DSM_COLOR_ETH:return TRACE_TYPE_ETH;
172                case TYPE_IPV4:         return TRACE_TYPE_NONE;
173                case TYPE_IPV6:         return TRACE_TYPE_NONE;
174        }
175        return ~0U;
176}
177
178uint8_t libtrace_to_erf_type(libtrace_linktype_t linktype)
179{
180        switch(linktype) {
181                case TRACE_TYPE_HDLC_POS: return TYPE_HDLC_POS;
182                case TRACE_TYPE_ETH:    return TYPE_ETH;
183                case TRACE_TYPE_ATM:    return TYPE_ATM;
184                case TRACE_TYPE_AAL5:   return TYPE_AAL5;
185               
186                /* Not technically correct! Could be IPv6 packet
187                 *
188                 * TODO: Maybe we want TRACE_TYPE_RAW_IPV4 and
189                 * TRACE_TYPE_RAW_IPV6 to replace TRACE_TYPE_NONE.
190                 * Still need a good way to figure out how to convert
191                 * TRACE_DLT_LINKTYPE_RAW into the correct type for the
192                 * IP version though :( */
193                case TRACE_TYPE_NONE:   return TYPE_IPV4;
194                /* Unsupported conversions */
195                case TRACE_TYPE_LLCSNAP:
196                case TRACE_TYPE_DUCK:
197                case TRACE_TYPE_80211_RADIO:
198                case TRACE_TYPE_80211_PRISM:
199                case TRACE_TYPE_80211:
200                case TRACE_TYPE_PFLOG:
201                case TRACE_TYPE_LINUX_SLL:
202                case TRACE_TYPE_PPP:
203                case TRACE_TYPE_POS:
204                case TRACE_TYPE_METADATA:
205                case TRACE_TYPE_NONDATA:
206                case TRACE_TYPE_OPENBSD_LOOP:
207                case TRACE_TYPE_UNKNOWN:
208                        break;
209        }
210        return 255;
211}
212
213libtrace_linktype_t arphrd_type_to_libtrace(unsigned int arphrd) {
214        switch(arphrd) {
215                case LIBTRACE_ARPHRD_ETHER: return TRACE_TYPE_ETH;     
216                case LIBTRACE_ARPHRD_EETHER: return TRACE_TYPE_ETH;     
217                case LIBTRACE_ARPHRD_IEEE80211: return TRACE_TYPE_80211;
218                case LIBTRACE_ARPHRD_IEEE80211_RADIOTAP: return TRACE_TYPE_80211_RADIO;
219                case LIBTRACE_ARPHRD_PPP: return TRACE_TYPE_NONE;
220                case LIBTRACE_ARPHRD_IPGRE: return TRACE_TYPE_NONE;
221                case LIBTRACE_ARPHRD_LOOPBACK: return TRACE_TYPE_ETH;
222                case LIBTRACE_ARPHRD_SIT: return TRACE_TYPE_ETH;
223                case LIBTRACE_ARPHRD_NONE: return TRACE_TYPE_NONE;
224        }
225        printf("Unknown ARPHRD %08x\n",arphrd);
226        return ~0U;
227}
228
229unsigned int libtrace_to_arphrd_type(libtrace_linktype_t linktype) {
230        switch(linktype) {
231                case TRACE_TYPE_ETH: return LIBTRACE_ARPHRD_ETHER;
232                case TRACE_TYPE_80211: return LIBTRACE_ARPHRD_IEEE80211;
233                case TRACE_TYPE_80211_RADIO: return LIBTRACE_ARPHRD_IEEE80211_RADIOTAP;
234                default: break;
235        }
236        return ~0U;
237}
238
239/** Prepends a Linux SLL header to the packet.
240 *
241 * Packets that don't support direction tagging are annoying, especially
242 * when we have direction tagging information!  So this converts the packet
243 * to TRACE_TYPE_LINUX_SLL which does support direction tagging.  This is a
244 * pcap style packet for the reason that it means it works with bpf filters.
245 *
246 * @note this will copy the packet, so use sparingly if possible.
247 */
248void promote_packet(libtrace_packet_t *packet)
249{
250        if (packet->trace->format->type == TRACE_FORMAT_PCAP) {
251                char *tmpbuffer;
252                libtrace_sll_header_t *hdr;
253
254                if (pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type))
255                        == TRACE_TYPE_LINUX_SLL) {
256                        /* This is already been promoted, so ignore it */
257                        return;
258                }
259
260                /* This should be easy, just prepend the header */
261                tmpbuffer= (char*)malloc(
262                                sizeof(libtrace_sll_header_t)
263                                +trace_get_capture_length(packet)
264                                +trace_get_framing_length(packet)
265                                );
266
267                hdr=(libtrace_sll_header_t*)((char*)tmpbuffer
268                        +trace_get_framing_length(packet));
269
270                hdr->halen=htons(6);
271                hdr->pkttype=TRACE_SLL_OUTGOING;
272
273                switch(pcap_linktype_to_libtrace(rt_to_pcap_linktype(packet->type))) {
274                        case TRACE_TYPE_NONE:
275                                trace_get_layer3(packet, &hdr->protocol, NULL);
276                                hdr->hatype = htons(LIBTRACE_ARPHRD_PPP);
277                                hdr->protocol=htons(hdr->protocol);
278                                break;
279                        case TRACE_TYPE_ETH:
280                                hdr->hatype = htons(LIBTRACE_ARPHRD_ETHER);
281                                hdr->protocol=htons(0x0060); /* ETH_P_LOOP */
282                                break;
283                        default:
284                                /* failed */
285                                return;
286                }
287                memcpy(tmpbuffer,packet->header,
288                                trace_get_framing_length(packet));
289                memcpy(tmpbuffer
290                                +sizeof(libtrace_sll_header_t)
291                                +trace_get_framing_length(packet),
292                                packet->payload,
293                                trace_get_capture_length(packet));
294                if (packet->buf_control == TRACE_CTRL_EXTERNAL) {
295                        packet->buf_control=TRACE_CTRL_PACKET;
296                }
297                else {
298                        free(packet->buffer);
299                }
300                packet->buffer=tmpbuffer;
301                packet->header=tmpbuffer;
302                packet->payload=tmpbuffer+trace_get_framing_length(packet);
303                packet->type=pcap_linktype_to_rt(TRACE_DLT_LINUX_SLL);
304                ((struct libtrace_pcapfile_pkt_hdr_t*) packet->header)->caplen+=
305                        sizeof(libtrace_sll_header_t);
306                ((struct libtrace_pcapfile_pkt_hdr_t*) packet->header)->wirelen+=
307                        sizeof(libtrace_sll_header_t);
308                trace_clear_cache(packet);
309                return;
310        }
311}
312
313/* Try and remove any extraneous encapsulation that may have been added to
314 * a packet. Effectively the opposite to promote_packet.
315 *
316 * Returns true if demotion was possible, false if not.
317 */
318bool demote_packet(libtrace_packet_t *packet)
319{
320        uint8_t type;
321        uint16_t ha_type, next_proto;
322        libtrace_sll_header_t *sll = NULL;
323        uint32_t remaining = 0;
324        char *tmp;
325        struct timeval tv;
326        static libtrace_t *trace = NULL;
327        switch(trace_get_link_type(packet)) {
328                case TRACE_TYPE_ATM:
329                        remaining=trace_get_capture_length(packet);
330                        packet->payload=trace_get_payload_from_atm(
331                                packet->payload,&type,&remaining);
332                        if (!packet->payload)
333                                return false;
334                        tmp=(char*)malloc(
335                                trace_get_capture_length(packet)
336                                +sizeof(libtrace_pcapfile_pkt_hdr_t)
337                                );
338
339                        tv=trace_get_timeval(packet);
340                        ((libtrace_pcapfile_pkt_hdr_t*)tmp)->ts_sec=tv.tv_sec;
341                        ((libtrace_pcapfile_pkt_hdr_t*)tmp)->ts_usec=tv.tv_usec;
342                        ((libtrace_pcapfile_pkt_hdr_t*)tmp)->wirelen
343                                = trace_get_wire_length(packet)-(trace_get_capture_length(packet)-remaining);
344                        ((libtrace_pcapfile_pkt_hdr_t*)tmp)->caplen
345                                = remaining;
346
347                        memcpy(tmp+sizeof(libtrace_pcapfile_pkt_hdr_t),
348                                        packet->payload,
349                                        (size_t)remaining);
350                        if (packet->buf_control == TRACE_CTRL_EXTERNAL) {
351                                packet->buf_control=TRACE_CTRL_PACKET;
352                        }
353                        else {
354                                free(packet->buffer);
355                        }
356                        packet->buffer=tmp;
357                        packet->header=tmp;
358                        packet->payload=tmp+sizeof(libtrace_pcapfile_pkt_hdr_t);
359                        packet->type=pcap_linktype_to_rt(TRACE_DLT_ATM_RFC1483);
360                       
361                        if (trace == NULL) {
362                                trace = trace_create_dead("pcapfile:-");
363                        }
364
365                        packet->trace=trace;
366
367                        /* Invalidate caches */
368                        trace_clear_cache(packet);
369                        return true;
370
371                case TRACE_TYPE_LINUX_SLL:
372                        sll = (libtrace_sll_header_t *)(packet->payload);
373
374                        ha_type = ntohs(sll->hatype);
375                        next_proto = ntohs(sll->protocol);
376               
377                        /* Preserved from older libtrace behaviour */
378                        if (ha_type == LIBTRACE_ARPHRD_PPP)
379                                packet->type = pcap_linktype_to_rt(TRACE_DLT_RAW);
380                        /* Don't decide trace type based on ha_type,
381                         * decide based on the protocol header that is
382                         * coming up!
383                         */
384                        else if (next_proto == TRACE_ETHERTYPE_LOOPBACK)
385                                packet->type = pcap_linktype_to_rt(TRACE_DLT_EN10MB);
386                        else if (next_proto == TRACE_ETHERTYPE_IP) 
387                                packet->type = pcap_linktype_to_rt(TRACE_DLT_RAW);
388                        else if (next_proto == TRACE_ETHERTYPE_IPV6)
389                                packet->type = pcap_linktype_to_rt(TRACE_DLT_RAW);
390                        else
391                                return false;
392
393                        /* Skip the Linux SLL header */
394                        packet->payload=(void*)((char*)packet->payload
395                                        +sizeof(libtrace_sll_header_t));
396                        trace_set_capture_length(packet,
397                                trace_get_capture_length(packet)
398                                        -sizeof(libtrace_sll_header_t));
399
400                        /* Invalidate caches */
401                        trace_clear_cache(packet);
402                        break;
403                default:
404                        return false;
405        }
406
407        /* Invalidate caches */
408        trace_clear_cache(packet);
409        return true;
410}
Note: See TracBrowser for help on using the repository browser.