summaryrefslogtreecommitdiffstats
path: root/msm8998/hal/src/PrefixParser.cpp
blob: d38bec0cd46a82be5d25832cf7d4d21c9a5ece1e (plain)
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
/*
 * Copyright (c) 2017, The Linux Foundation. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *    * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above
 *      copyright notice, this list of conditions and the following
 *      disclaimer in the documentation and/or other materials provided
 *      with the distribution.
 *    * Neither the name of The Linux Foundation nor the names of its
 *      contributors may be used to endorse or promote products derived
 *      from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/* External Includes */
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <vector>

/* Internal Includes */
#include "IOffloadManager.h"
#include "PrefixParser.h"

/* Avoiding namespace pollution */
using IP_FAM = ::IOffloadManager::IP_FAM;
using Prefix = ::IOffloadManager::Prefix;

using ::std::string;
using ::std::vector;


/* ------------------------------ PUBLIC ------------------------------------ */
PrefixParser::PrefixParser() {
    mLastErr = "No Err";
} /* PrefixParser */

bool PrefixParser::add(vector<string> in) {
    return add(in, IP_FAM::INVALID);
} /* add */

bool PrefixParser::add(string in) {
    return add(in, IP_FAM::INVALID);
} /* add */

bool PrefixParser::addV4(string in) {
    return add(in, IP_FAM::V4);
} /* addV4 */

bool PrefixParser::addV4(vector<string> in) {
    return add(in, IP_FAM::V4);
} /* addV4 */

bool PrefixParser::addV6(string in) {
    return add(in, IP_FAM::V6);
} /* addV6 */

bool PrefixParser::addV6(vector<string> in) {
    for (size_t i = 0; i < in.size(); i++) {
        if (!addV6(in[i]))
            return false;
    }
    return true;
} /* addV6 */

int PrefixParser::size() {
    return mPrefixes.size();
} /* size */

bool PrefixParser::allAreFullyQualified() {
    for (size_t i = 0; i < mPrefixes.size(); i++) {
        if (mPrefixes[i].fam == IP_FAM::V4) {
            uint32_t masked = mPrefixes[i].v4Addr & mPrefixes[i].v4Mask;
            if (masked != mPrefixes[i].v4Addr)
                return false;
        } else {
            uint32_t masked[4];
            masked[0] = mPrefixes[i].v6Addr[0] & mPrefixes[i].v6Mask[0];
            masked[1] = mPrefixes[i].v6Addr[1] & mPrefixes[i].v6Mask[1];
            masked[2] = mPrefixes[i].v6Addr[2] & mPrefixes[i].v6Mask[2];
            masked[3] = mPrefixes[i].v6Addr[3] & mPrefixes[i].v6Mask[3];
            for (int j = 0; j < 4; j++) {
                if (masked[j] != mPrefixes[i].v6Addr[j])
                    return false;
            }
        }
    }
    return true;
} /* allAreFullyQualified */

Prefix PrefixParser::getFirstPrefix() {
    if (size() >= 1)
        return mPrefixes[0];
    return makeBlankPrefix(IP_FAM::INVALID);
} /* getFirstPrefix */

string PrefixParser::getLastErrAsStr() {
    return mLastErr;
} /* getLastErrAsStr */


/* ------------------------------ PRIVATE ----------------------------------- */
bool PrefixParser::add(vector<string> in, IP_FAM famHint) {
    if (in.size() == 0)
        return false;

    for (size_t i = 0; i < in.size(); i++) {
        if (!add(in[i], famHint))
            return false;
    }
    return true;
} /* add */

bool PrefixParser::add(string in, IP_FAM famHint) {
    if (in.length() == 0) {
        mLastErr = "Failed to parse string, length = 0...";
        return false;
    }

    if (famHint == IP_FAM::INVALID)
        famHint = guessIPFamily(in);

    string subnet;
    string addr;

    if (!splitIntoAddrAndMask(in, addr, subnet)) {
        mLastErr = "Failed to split into Address and Mask(" + in + ")";
        return false;
    }

    int mask = parseSubnetMask(subnet, famHint);
    if (!isMaskValid(mask, famHint)) {
        mLastErr = "Invalid mask";
        return false;
    }

    Prefix pre = makeBlankPrefix(famHint);

    if (famHint == IP_FAM::V4) {
        if (!parseV4Addr(addr, pre)) {
            mLastErr = "Failed to parse V4 Address(" + addr + ")";
            return false;
        }
    } else if (!parseV6Addr(addr, pre)) {
        mLastErr = "Failed to parse V6 Address(" + addr + ")";
        return false;
    }

    if (famHint == IP_FAM::V4 && !populateV4Mask(mask, pre)) {
        mLastErr = "Failed to populate IPv4 Mask(" + std::to_string(mask)
                + ", " + addr + ")";
        return false;
    } else if (!populateV6Mask(mask, pre)) {
        mLastErr = "Failed to populate IPv6 Mask(" + std::to_string(mask)
                + ", " + addr + ")";
        return false;
    }

    mPrefixes.push_back(pre);
    return true;
} /* add */

/* Assumption (based on man inet_pton)
 *
 * X represents a hex character
 * d represents a base 10 digit
 * / represents the start of the subnet mask
 *              (assume that it can be left off of all below combinations)
 *
 * IPv4 Addresses always look like the following:
 *      ddd.ddd.ddd.ddd/dd
 *
 * IPv6 Addresses can look a few different ways:
 *      x:x:x:x:x:x:x:x/ddd
 *      x::x/ddd
 *      x:x:x:x:x:x:d.d.d.d/ddd
 *
 * Therefore, if a presentation of an IP Address contains a colon, then it
 * may not be a valid IPv6, but, it is definitely not valid IPv4.  If a
 * presentation of an IP Address does not contain a colon, then it may not be
 * a valid IPv4, but, it is definitely not IPv6.
 */
IP_FAM PrefixParser::guessIPFamily(string in) {
    size_t found = in.find(":");
    if (found != string::npos)
        return IP_FAM::V6;
    return IP_FAM::V4;
} /* guessIPFamily */

bool PrefixParser::splitIntoAddrAndMask(string in, string &addr, string &mask) {
    size_t pos = in.find("/");

    if (pos != string::npos && pos >= 1) {
        /* addr is now everything up until the first / */
        addr = in.substr(0, pos);
    } else if (pos == string::npos) {
        /* There is no /, so the entire input is an address */
        addr = in;
    } else {
        /* There was nothing before the /, not recoverable */
        return false;
    }

    if (pos != string::npos && pos < in.size()) {
        /* There is a / and it is not the last character.  Everything after /
         * must be the subnet.
         */
        mask = in.substr(pos + 1);
    } else if (pos != string::npos && pos == in.size()) {
        /* There is a /, but it is the last character.  This is garbage, but,
         * we may still be able to interpret the address so we will throw it
         * out.
         */
        mask = "";
    } else if (pos == string::npos) {
        /* There is no /, therefore, there is no subnet */
        mask = "";
    } else {
        /* This really shouldn't be possible because it would imply that find
         * returned a position larger than the size of the input.  Just
         * preserving sanity that mask is always initialized.
         */
        mask = "";
    }

    return true;
} /* splitIntoAddrAndMask */

int PrefixParser::parseSubnetMask(string in, IP_FAM famHint) {
    if (in.empty())
        /* Treat no subnet mask as fully qualified */
        return (famHint == IP_FAM::V6) ? 128 : 32;
    return atoi(in.c_str());
} /* parseSubnetMask */

bool PrefixParser::parseV4Addr(string in, Prefix &out) {
    struct sockaddr_in sa;

    int ret = inet_pton(AF_INET, in.c_str(), &(sa.sin_addr));

    if (ret < 0) {
        /* errno would be valid */
        return false;
    } else if (ret == 0) {
        /* input was not a valid IP address */
        return false;
    }

    /* Address in network byte order */
    out.v4Addr = htonl(sa.sin_addr.s_addr);
    return true;
} /* parseV4Addr */

bool PrefixParser::parseV6Addr(string in, Prefix &out) {
    struct sockaddr_in6 sa;

    int ret = inet_pton(AF_INET6, in.c_str(), &(sa.sin6_addr));

    if (ret < 0) {
        /* errno would be valid */
        return false;
    } else if (ret == 0) {
        /* input was not a valid IP address */
        return false;
    }

    /* Translate unsigned chars to unsigned ints to match IPA
     *
     * TODO there must be a better way to do this beyond bit fiddling
     * Maybe a Union since we've already made the assumption that the data
     * structures match?
     */
    out.v6Addr[0] = (sa.sin6_addr.s6_addr[0] << 24) |
                    (sa.sin6_addr.s6_addr[1] << 16) |
                    (sa.sin6_addr.s6_addr[2] << 8) |
                    (sa.sin6_addr.s6_addr[3]);
    out.v6Addr[1] = (sa.sin6_addr.s6_addr[4] << 24) |
                    (sa.sin6_addr.s6_addr[5] << 16) |
                    (sa.sin6_addr.s6_addr[6] << 8) |
                    (sa.sin6_addr.s6_addr[7]);
    out.v6Addr[2] = (sa.sin6_addr.s6_addr[8] << 24) |
                    (sa.sin6_addr.s6_addr[9] << 16) |
                    (sa.sin6_addr.s6_addr[10] << 8) |
                    (sa.sin6_addr.s6_addr[11]);
    out.v6Addr[3] = (sa.sin6_addr.s6_addr[12] << 24) |
                    (sa.sin6_addr.s6_addr[13] << 16) |
                    (sa.sin6_addr.s6_addr[14] << 8) |
                    (sa.sin6_addr.s6_addr[15]);
    return true;
} /* parseV6Addr */

bool PrefixParser::populateV4Mask(int mask, Prefix &out) {
    if (mask < 0 || mask > 32)
        return false;
    out.v4Mask = createMask(mask);
    return true;
} /* populateV4Mask */

bool PrefixParser::populateV6Mask(int mask, Prefix &out) {
    if (mask < 0 || mask > 128)
        return false;

    for (int i = 0; i < 4; i++) {
        out.v6Mask[i] = createMask(mask);
        mask = (mask > 32) ? mask - 32 : 0;
    }

    return true;
} /* populateV6Mask */

uint32_t PrefixParser::createMask(int mask) {
    uint32_t ret = 0;

    if (mask >= 32) {
        ret = ~ret;
        return ret;
    }

    for (int i = 0; i < 32; i++) {
        if (i < mask)
            ret = (ret << 1) | 1;
        else
            ret = (ret << 1);
    }

    return ret;
} /* createMask */

Prefix PrefixParser::makeBlankPrefix(IP_FAM famHint) {
    Prefix ret;

    ret.fam = famHint;

    ret.v4Addr = 0;
    ret.v4Mask = 0;

    ret.v6Addr[0] = 0;
    ret.v6Addr[1] = 0;
    ret.v6Addr[2] = 0;
    ret.v6Addr[3] = 0;

    ret.v6Mask[0] = 0;
    ret.v6Mask[1] = 0;
    ret.v6Mask[2] = 0;
    ret.v6Mask[3] = 0;

    return ret;
} /* makeBlankPrefix */

bool PrefixParser::isMaskValid(int mask, IP_FAM fam) {
    if (mask < 0) {
        mLastErr = "Failed parse subnet mask(" + std::to_string(mask) + ")";
        return false;
    } else if (mask == 0) {
        mLastErr = "Subnet mask cannot be 0(" + std::to_string(mask) + ")";
        return false;
    } else if (fam == IP_FAM::V4 && mask > 32) {
        mLastErr = "Interpreted address as V4 but mask was too large("
                + std::to_string(mask) + ")";
        return false;
    } else if (fam == IP_FAM::V6 && mask > 128) {
        mLastErr = "Interpreted address as V6 but mask was too large("
                + std::to_string(mask) + ")";
        return false;
    }

    return true;
} /* isMaskValid */