summaryrefslogtreecommitdiff
path: root/msm8998/hal/src/PrefixParser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'msm8998/hal/src/PrefixParser.cpp')
-rw-r--r--msm8998/hal/src/PrefixParser.cpp375
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 */