This reverts commit 98c3540df1
.
Revert needed due Wifi Offload service crashing device and cause soft reboot
391 lines
12 KiB
C++
391 lines
12 KiB
C++
/*
|
|
* 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 */
|
|
|
|
Prefix PrefixParser::getFirstPrefix(IP_FAM famHint) {
|
|
if (size() >= 1)
|
|
return mPrefixes[0];
|
|
return makeBlankPrefix(famHint);
|
|
} /* 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 */
|