diff options
Diffstat (limited to 'msm8998/hal/src/PrefixParser.cpp')
-rw-r--r-- | msm8998/hal/src/PrefixParser.cpp | 375 |
1 files changed, 375 insertions, 0 deletions
diff --git a/msm8998/hal/src/PrefixParser.cpp b/msm8998/hal/src/PrefixParser.cpp new file mode 100644 index 0000000..60aae08 --- /dev/null +++ b/msm8998/hal/src/PrefixParser.cpp @@ -0,0 +1,375 @@ +/* + * 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) { + 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 (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)) + 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 */ |