File: packet.cpp

package info (click to toggle)
ostinato 1.3.0-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 4,840 kB
  • sloc: cpp: 46,226; makefile: 8
file content (117 lines) | stat: -rw-r--r-- 3,556 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
Copyright (C) 2023 Srivats P.

This file is part of "Ostinato"

This is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

#include "packet.h"

using namespace Packet;

quint16 Packet::l4ChecksumOffset(const uchar *pktData, int pktLen)
{
    Parser parser(pktData, pktLen);
    quint16 offset = kEthTypeOffset;

    // Skip VLANs, if any
    quint16 ethType = parser.field16(offset);
    if (!parser.ok()) return 0;

    // TODO: support 802.3 frames
    if (ethType <= 1500)
        return 0;

    while (kVlanEthTypes.contains(ethType)) {
        offset += kVlanTagSize;
        ethType = parser.field16(offset);
        if (!parser.ok()) return 0;
    }
    offset += kEthTypeSize;

    // XXX: offset now points to Eth payload

    // Skip MPLS tags, if any
    if (ethType == kMplsEthType) {
        while (1) {
            quint32 mplsTag = parser.field32(offset);
            if (!parser.ok()) return 0;
            offset += kMplsTagSize;
            if (mplsTag & 0x100) { // BOS bit
                quint32 nextWord = parser.field32(offset);
                if (!parser.ok()) return 0;
                if (nextWord == 0) { // PW Control Word
                    offset += kMplsTagSize;
                    ethType = 0;
                    break;
                }
                quint8 firstPayloadNibble = nextWord >> 28;
                if (firstPayloadNibble == 0x4)
                    ethType = kIp4EthType;
                else if (firstPayloadNibble == 0x6)
                    ethType = kIp6EthType;
                else
                    ethType = 0;
                break;
            }
        }
    }

    quint8 ipProto = 0;
    if (ethType == kIp4EthType) {
        ipProto = parser.field8(offset + kIp4ProtocolOffset);
        if (!parser.ok()) return 0;

        quint8 ipHdrLen = parser.field8(offset) & 0x0F;
        if (!parser.ok()) return 0;
        offset += 4*ipHdrLen;
    } else if (ethType == kIp6EthType) {
        ipProto = parser.field8(offset + kIp6NextHeaderOffset);
        if (!parser.ok()) return 0;
        offset += kIp6HeaderSize;

        // XXX: offset now points to IPv6 payload

        // Skip IPv6 extension headers, if any
        while (kIp6ExtensionHeaders.contains(ipProto)) {
            ipProto = parser.field8(offset + kIp6ExtNextHeaderOffset);
            if (!parser.ok()) return 0;

            quint16 extHdrLen = parser.field8(offset + kIp6ExtLengthOffset);
            offset += 8 + 8*extHdrLen;
        }
    } else {
        // Non-IP
        // TODO: support MPLS PW with Eth payload
        return 0;
    }

    // XXX: offset now points to IP payload

    if (ipProto == kIpProtoTcp) {
        parser.field16(offset + kTcpChecksumOffset);
        if (!parser.ok()) return 0;

        return offset + kTcpChecksumOffset;
    } else if (ipProto == kIpProtoUdp) {
        parser.field16(offset + kUdpChecksumOffset);
        if (!parser.ok()) return 0;

        return offset + kUdpChecksumOffset;
    }

    // No L4
    return 0;
}