| /* | |
| * Copyright (c) 2013 ARM Limited | |
| * All rights reserved | |
| * | |
| * The license below extends only to copyright in the software and shall | |
| * not be construed as granting a license to any other intellectual | |
| * property including but not limited to intellectual property relating | |
| * to a hardware implementation of the functionality of the software | |
| * licensed hereunder. You may use the software subject to the license | |
| * terms below provided that you ensure that this notice is replicated | |
| * unmodified and in its entirety in all distributions of the software, | |
| * modified or unmodified, in source code or in binary form. | |
| * | |
| * Copyright (c) 2002-2005 The Regents of The University of Michigan | |
| * Copyright (c) 2010 Advanced Micro Devices, Inc. | |
| * 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 copyright holders 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE 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. | |
| */ | |
| #include "base/inet.hh" | |
| #include <cstddef> | |
| #include <cstdio> | |
| #include <sstream> | |
| #include <string> | |
| #include "base/cprintf.hh" | |
| #include "base/logging.hh" | |
| #include "base/types.hh" | |
| namespace gem5 | |
| { | |
| GEM5_DEPRECATED_NAMESPACE(Net, networking); | |
| namespace networking | |
| { | |
| EthAddr::EthAddr() | |
| { | |
| std::memset(data, 0, ETH_ADDR_LEN); | |
| } | |
| EthAddr::EthAddr(const uint8_t ea[ETH_ADDR_LEN]) | |
| { | |
| for (int i = 0; i < ETH_ADDR_LEN; ++i) | |
| data[i] = ea[i]; | |
| } | |
| EthAddr::EthAddr(const eth_addr &ea) | |
| { | |
| for (int i = 0; i < ETH_ADDR_LEN; ++i) | |
| data[i] = ea.data[i]; | |
| } | |
| EthAddr::EthAddr(const std::string &addr) | |
| { | |
| parse(addr); | |
| } | |
| const EthAddr & | |
| EthAddr::operator=(const eth_addr &ea) | |
| { | |
| *data = *ea.data; | |
| return *this; | |
| } | |
| const EthAddr & | |
| EthAddr::operator=(const std::string &addr) | |
| { | |
| parse(addr); | |
| return *this; | |
| } | |
| void | |
| EthAddr::parse(const std::string &addr) | |
| { | |
| // the hack below is to make sure that ETH_ADDR_LEN is 6 otherwise | |
| // the sscanf function won't work. | |
| int bytes[ETH_ADDR_LEN == 6 ? ETH_ADDR_LEN : -1]; | |
| if (sscanf(addr.c_str(), "%x:%x:%x:%x:%x:%x", &bytes[0], &bytes[1], | |
| &bytes[2], &bytes[3], &bytes[4], &bytes[5]) != ETH_ADDR_LEN) { | |
| std::memset(data, 0xff, ETH_ADDR_LEN); | |
| return; | |
| } | |
| for (int i = 0; i < ETH_ADDR_LEN; ++i) { | |
| if (bytes[i] & ~0xff) { | |
| std::memset(data, 0xff, ETH_ADDR_LEN); | |
| return; | |
| } | |
| data[i] = bytes[i]; | |
| } | |
| } | |
| std::string | |
| EthAddr::string() const | |
| { | |
| std::stringstream stream; | |
| stream << *this; | |
| return stream.str(); | |
| } | |
| bool | |
| operator==(const EthAddr &left, const EthAddr &right) | |
| { | |
| return !std::memcmp(left.bytes(), right.bytes(), ETH_ADDR_LEN); | |
| } | |
| std::ostream & | |
| operator<<(std::ostream &stream, const EthAddr &ea) | |
| { | |
| const uint8_t *a = ea.addr(); | |
| ccprintf(stream, "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]); | |
| return stream; | |
| } | |
| std::string | |
| IpAddress::string() const | |
| { | |
| std::stringstream stream; | |
| stream << *this; | |
| return stream.str(); | |
| } | |
| bool | |
| operator==(const IpAddress &left, const IpAddress &right) | |
| { | |
| return left.ip() == right.ip(); | |
| } | |
| std::ostream & | |
| operator<<(std::ostream &stream, const IpAddress &ia) | |
| { | |
| uint32_t ip = ia.ip(); | |
| ccprintf(stream, "%x.%x.%x.%x", | |
| (uint8_t)(ip >> 24), (uint8_t)(ip >> 16), | |
| (uint8_t)(ip >> 8), (uint8_t)(ip >> 0)); | |
| return stream; | |
| } | |
| std::string | |
| IpNetmask::string() const | |
| { | |
| std::stringstream stream; | |
| stream << *this; | |
| return stream.str(); | |
| } | |
| bool | |
| operator==(const IpNetmask &left, const IpNetmask &right) | |
| { | |
| return (left.ip() == right.ip()) && | |
| (left.netmask() == right.netmask()); | |
| } | |
| std::ostream & | |
| operator<<(std::ostream &stream, const IpNetmask &in) | |
| { | |
| ccprintf(stream, "%s/%d", (const IpAddress &)in, in.netmask()); | |
| return stream; | |
| } | |
| std::string | |
| IpWithPort::string() const | |
| { | |
| std::stringstream stream; | |
| stream << *this; | |
| return stream.str(); | |
| } | |
| bool | |
| operator==(const IpWithPort &left, const IpWithPort &right) | |
| { | |
| return (left.ip() == right.ip()) && (left.port() == right.port()); | |
| } | |
| std::ostream & | |
| operator<<(std::ostream &stream, const IpWithPort &iwp) | |
| { | |
| ccprintf(stream, "%s:%d", (const IpAddress &)iwp, iwp.port()); | |
| return stream; | |
| } | |
| uint16_t | |
| cksum(const IpPtr &ptr) | |
| { | |
| int sum = ip_cksum_add(ptr->bytes(), ptr->hlen(), 0); | |
| return ip_cksum_carry(sum); | |
| } | |
| uint16_t | |
| __tu_cksum(const IpPtr &ip) | |
| { | |
| int tcplen = ip->len() - ip->hlen(); | |
| int sum = ip_cksum_add(ip->payload(), tcplen, 0); | |
| sum = ip_cksum_add(&ip->ip_src, 8, sum); // source and destination | |
| sum += htons(ip->ip_p + tcplen); | |
| return ip_cksum_carry(sum); | |
| } | |
| uint16_t | |
| __tu_cksum6(const Ip6Ptr &ip6) | |
| { | |
| int tcplen = ip6->plen() - ip6->extensionLength(); | |
| int sum = ip_cksum_add(ip6->payload(), tcplen, 0); | |
| sum = ip_cksum_add(ip6->src(), 32, sum); | |
| sum += htons(ip6->proto() + tcplen); | |
| return ip_cksum_carry(sum); | |
| } | |
| uint16_t | |
| cksum(const TcpPtr &tcp) | |
| { | |
| if (IpPtr(tcp.packet())) { | |
| return __tu_cksum(IpPtr(tcp.packet())); | |
| } else if (Ip6Ptr(tcp.packet())) { | |
| return __tu_cksum6(Ip6Ptr(tcp.packet())); | |
| } else { | |
| panic("Unrecognized IP packet format"); | |
| } | |
| // Should never reach here | |
| return 0; | |
| } | |
| uint16_t | |
| cksum(const UdpPtr &udp) | |
| { | |
| if (IpPtr(udp.packet())) { | |
| return __tu_cksum(IpPtr(udp.packet())); | |
| } else if (Ip6Ptr(udp.packet())) { | |
| return __tu_cksum6(Ip6Ptr(udp.packet())); | |
| } else { | |
| panic("Unrecognized IP packet format"); | |
| } | |
| return 0; | |
| } | |
| bool | |
| IpHdr::options(std::vector<const IpOpt *> &vec) const | |
| { | |
| vec.clear(); | |
| const uint8_t *data = bytes() + sizeof(struct ip_hdr); | |
| int all = hlen() - sizeof(struct ip_hdr); | |
| while (all > 0) { | |
| const IpOpt *opt = (const IpOpt *)data; | |
| int len = opt->len(); | |
| if (all < len) | |
| return false; | |
| vec.push_back(opt); | |
| all -= len; | |
| data += len; | |
| } | |
| return true; | |
| } | |
| namespace | |
| { | |
| bool | |
| ip6Extension(uint8_t nxt) | |
| { | |
| return nxt == IP_PROTO_HOPOPTS || nxt == IP_PROTO_ROUTING || | |
| nxt == IP_PROTO_FRAGMENT || nxt == IP_PROTO_AH || | |
| nxt == IP_PROTO_ESP || nxt == IP_PROTO_DSTOPTS; | |
| } | |
| } // anonymous namespace | |
| /* Scan the IP6 header for all header extensions | |
| * and return the number of headers found | |
| */ | |
| int | |
| Ip6Hdr::extensionLength() const | |
| { | |
| const uint8_t *data = bytes() + IP6_HDR_LEN; | |
| uint8_t nxt = ip6_nxt; | |
| int len = 0; | |
| int all = plen(); | |
| while (ip6Extension(nxt)) { | |
| const Ip6Opt *ext = (const Ip6Opt *)data; | |
| nxt = ext->nxt(); | |
| len += ext->len(); | |
| data += ext->len(); | |
| all -= ext->len(); | |
| assert(all >= 0); | |
| } | |
| return len; | |
| } | |
| /* Scan the IP6 header for a particular extension | |
| * header type and return a pointer to it if it | |
| * exists, otherwise return NULL | |
| */ | |
| const Ip6Opt* | |
| Ip6Hdr::getExt(uint8_t ext_type) const | |
| { | |
| const uint8_t *data = bytes() + IP6_HDR_LEN; | |
| uint8_t nxt = ip6_nxt; | |
| Ip6Opt* opt = NULL; | |
| int all = plen(); | |
| while (ip6Extension(nxt)) { | |
| opt = (Ip6Opt *)data; | |
| if (nxt == ext_type) { | |
| break; | |
| } | |
| nxt = opt->nxt(); | |
| data += opt->len(); | |
| all -= opt->len(); | |
| opt = NULL; | |
| assert(all >= 0); | |
| } | |
| return (const Ip6Opt*)opt; | |
| } | |
| /* Scan the IP6 header and any extension headers | |
| * to find what type of Layer 4 header exists | |
| * after this header | |
| */ | |
| uint8_t | |
| Ip6Hdr::proto() const | |
| { | |
| const uint8_t *data = bytes() + IP6_HDR_LEN; | |
| uint8_t nxt = ip6_nxt; | |
| int all = plen(); | |
| while (ip6Extension(nxt)) { | |
| const Ip6Opt *ext = (const Ip6Opt *)data; | |
| nxt = ext->nxt(); | |
| data += ext->len(); | |
| all -= ext->len(); | |
| assert(all >= 0); | |
| } | |
| return nxt; | |
| } | |
| bool | |
| TcpHdr::options(std::vector<const TcpOpt *> &vec) const | |
| { | |
| vec.clear(); | |
| const uint8_t *data = bytes() + sizeof(struct tcp_hdr); | |
| int all = off() - sizeof(struct tcp_hdr); | |
| while (all > 0) { | |
| const TcpOpt *opt = (const TcpOpt *)data; | |
| int len = opt->len(); | |
| if (all < len) | |
| return false; | |
| vec.push_back(opt); | |
| all -= len; | |
| data += len; | |
| } | |
| return true; | |
| } | |
| int | |
| hsplit(const EthPacketPtr &ptr) | |
| { | |
| int split_point = 0; | |
| IpPtr ip(ptr); | |
| Ip6Ptr ip6(ptr); | |
| if (ip) { | |
| split_point = ip.pstart(); | |
| TcpPtr tcp(ip); | |
| if (tcp) | |
| split_point = tcp.pstart(); | |
| UdpPtr udp(ip); | |
| if (udp) | |
| split_point = udp.pstart(); | |
| } else if (ip6) { | |
| split_point = ip6.pstart(); | |
| TcpPtr tcp(ip6); | |
| if (tcp) | |
| split_point = tcp.pstart(); | |
| UdpPtr udp(ip6); | |
| if (udp) | |
| split_point = udp.pstart(); | |
| } | |
| return split_point; | |
| } | |
| } // namespace networking | |
| } // namespace gem5 |