inet.hh revision 1762
12SN/A/*
21762SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
32SN/A * All rights reserved.
42SN/A *
52SN/A * Redistribution and use in source and binary forms, with or without
62SN/A * modification, are permitted provided that the following conditions are
72SN/A * met: redistributions of source code must retain the above copyright
82SN/A * notice, this list of conditions and the following disclaimer;
92SN/A * redistributions in binary form must reproduce the above copyright
102SN/A * notice, this list of conditions and the following disclaimer in the
112SN/A * documentation and/or other materials provided with the distribution;
122SN/A * neither the name of the copyright holders nor the names of its
132SN/A * contributors may be used to endorse or promote products derived from
142SN/A * this software without specific prior written permission.
152SN/A *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu */
282665Ssaidi@eecs.umich.edu
292665Ssaidi@eecs.umich.edu#ifndef __BASE_INET_HH__
302SN/A#define __BASE_INET_HH__
312SN/A
321388SN/A#include <iosfwd>
332SN/A#include <string>
342SN/A#include <utility>
352SN/A#include <vector>
361191SN/A
371191SN/A#include "base/range.hh"
381191SN/A#include "dev/etherpkt.hh"
391388SN/A#include "sim/host.hh"
405529Snate@binkert.org
411717SN/A#include "dnet/os.h"
422651Ssaidi@eecs.umich.edu#include "dnet/eth.h"
432680Sktlim@umich.edu#include "dnet/ip.h"
441977SN/A#include "dnet/ip6.h"
455529Snate@binkert.org#include "dnet/addr.h"
463144Shsul@eecs.umich.edu#include "dnet/arp.h"
472190SN/A#include "dnet/icmp.h"
4856SN/A#include "dnet/tcp.h"
492190SN/A#include "dnet/udp.h"
502SN/A#include "dnet/intf.h"
512359SN/A#include "dnet/route.h"
522359SN/A#include "dnet/fw.h"
532359SN/A#include "dnet/blob.h"
542SN/A#include "dnet/rand.h"
552SN/A
562SN/Anamespace Net {
572SN/A
582SN/A/*
592SN/A * Ethernet Stuff
602SN/A */
612SN/Astruct EthAddr : protected eth_addr
622SN/A{
635606Snate@binkert.org  protected:
645606Snate@binkert.org    void parse(const std::string &addr);
655606Snate@binkert.org
663126Sktlim@umich.edu  public:
673126Sktlim@umich.edu    EthAddr();
685606Snate@binkert.org    EthAddr(const uint8_t ea[ETH_ADDR_LEN]);
693126Sktlim@umich.edu    EthAddr(const eth_addr &ea);
703126Sktlim@umich.edu    EthAddr(const std::string &addr);
712356SN/A    const EthAddr &operator=(const eth_addr &ea);
722356SN/A    const EthAddr &operator=(const std::string &addr);
732356SN/A
742367SN/A    int size() const { return sizeof(eth_addr); }
752356SN/A
765100Ssaidi@eecs.umich.edu    const uint8_t *bytes() const { return &data[0]; }
772367SN/A    uint8_t *bytes() { return &data[0]; }
782356SN/A
792356SN/A    const uint8_t *addr() const { return &data[0]; }
802356SN/A    bool unicast() const { return data[0] == 0x00; }
812367SN/A    bool multicast() const { return data[0] == 0x01; }
822367SN/A    bool broadcast() const { return data[0] == 0xff; }
832367SN/A    std::string string() const;
842367SN/A
852356SN/A    operator uint64_t() const
865606Snate@binkert.org    {
872356SN/A        uint64_t reg = 0;
882356SN/A        reg |= ((uint64_t)data[0]) << 40;
892356SN/A        reg |= ((uint64_t)data[1]) << 32;
905336Shines@cs.fsu.edu        reg |= ((uint64_t)data[2]) << 24;
912356SN/A        reg |= ((uint64_t)data[3]) << 16;
924873Sstever@eecs.umich.edu        reg |= ((uint64_t)data[4]) << 8;
932356SN/A        reg |= ((uint64_t)data[5]) << 0;
942356SN/A        return reg;
951858SN/A    }
961400SN/A
975712Shsul@eecs.umich.edu};
985712Shsul@eecs.umich.edu
995529Snate@binkert.orgstd::ostream &operator<<(std::ostream &stream, const EthAddr &ea);
1003661Srdreslin@umich.edubool operator==(const EthAddr &left, const EthAddr &right);
1012SN/A
1021400SN/Astruct EthHdr : public eth_hdr
1035712Shsul@eecs.umich.edu{
1045529Snate@binkert.org    uint16_t type() const { return ntohs(eth_type); }
1053661Srdreslin@umich.edu    const EthAddr &src() const { return *(EthAddr *)&eth_src; }
1062SN/A    const EthAddr &dst() const { return *(EthAddr *)&eth_dst; }
1072SN/A
1082359SN/A    int size() const { return sizeof(eth_hdr); }
1091062SN/A
1105712Shsul@eecs.umich.edu    const uint8_t *bytes() const { return (const uint8_t *)this; }
1115712Shsul@eecs.umich.edu    const uint8_t *payload() const { return bytes() + size(); }
1125712Shsul@eecs.umich.edu    uint8_t *bytes() { return (uint8_t *)this; }
1135712Shsul@eecs.umich.edu    uint8_t *payload() { return bytes() + size(); }
1145712Shsul@eecs.umich.edu};
1152SN/A
1162SN/Aclass EthPtr
1172SN/A{
1185712Shsul@eecs.umich.edu  protected:
1195712Shsul@eecs.umich.edu    friend class IpPtr;
1202SN/A    PacketPtr p;
1212SN/A
1222SN/A  public:
1232SN/A    EthPtr() {}
1241354SN/A    EthPtr(const PacketPtr &ptr) : p(ptr) { }
1252SN/A
126503SN/A    EthHdr *operator->() { return (EthHdr *)p->data; }
1272SN/A    EthHdr &operator*() { return *(EthHdr *)p->data; }
1282SN/A    operator EthHdr *() { return (EthHdr *)p->data; }
1292SN/A
1302SN/A    const EthHdr *operator->() const { return (const EthHdr *)p->data; }
1315606Snate@binkert.org    const EthHdr &operator*() const { return *(const EthHdr *)p->data; }
1325606Snate@binkert.org    operator const EthHdr *() const { return (const EthHdr *)p->data; }
1335606Snate@binkert.org
1345606Snate@binkert.org    const EthPtr &operator=(const PacketPtr &ptr) { p = ptr; return *this; }
1355606Snate@binkert.org
1365606Snate@binkert.org    const PacketPtr packet() const { return p; }
1375606Snate@binkert.org    PacketPtr packet() { return p; }
1382SN/A    bool operator!() const { return !p; }
1391400SN/A    operator bool() const { return p; }
1405606Snate@binkert.org};
1415606Snate@binkert.org
1422SN/A/*
1432SN/A * IP Stuff
1442SN/A */
1452SN/Astruct IpOpt;
1462SN/Astruct IpHdr : public ip_hdr
1475606Snate@binkert.org{
1485606Snate@binkert.org    uint8_t  version() const { return ip_v; }
1495606Snate@binkert.org    uint8_t  hlen() const { return ip_hl * 4; }
1505606Snate@binkert.org    uint8_t  tos() const { return ip_tos; }
1512SN/A    uint16_t len() const { return ntohs(ip_len); }
1522SN/A    uint16_t id() const { return ntohs(ip_id); }
153124SN/A    uint16_t frag_flags() const { return ntohs(ip_off) >> 13; }
1541354SN/A    uint16_t frag_off() const { return ntohs(ip_off) & 0x1fff; }
155124SN/A    uint8_t  ttl() const { return ip_ttl; }
156124SN/A    uint8_t  proto() const { return ip_p; }
157124SN/A    uint16_t sum() const { return ip_sum; }
158124SN/A    uint32_t src() const { return ntohl(ip_src); }
159124SN/A    uint32_t dst() const { return ntohl(ip_dst); }
160124SN/A
1615606Snate@binkert.org    void sum(uint16_t sum) { ip_sum = sum; }
1625606Snate@binkert.org
1635606Snate@binkert.org    bool options(std::vector<const IpOpt *> &vec) const;
1645606Snate@binkert.org
1655606Snate@binkert.org    int size() const { return hlen(); }
1665606Snate@binkert.org    const uint8_t *bytes() const { return (const uint8_t *)this; }
1675606Snate@binkert.org    const uint8_t *payload() const { return bytes() + size(); }
168124SN/A    uint8_t *bytes() { return (uint8_t *)this; }
1691400SN/A    uint8_t *payload() { return bytes() + size(); }
1705606Snate@binkert.org};
171124SN/A
172124SN/Aclass IpPtr
173124SN/A{
174124SN/A  protected:
175124SN/A    friend class TcpPtr;
1765606Snate@binkert.org    friend class UdpPtr;
1775606Snate@binkert.org    PacketPtr p;
1785606Snate@binkert.org
1795606Snate@binkert.org    const IpHdr *h() const
180124SN/A    { return (const IpHdr *)(p->data + sizeof(eth_hdr)); }
181124SN/A    IpHdr *h() { return (IpHdr *)(p->data + sizeof(eth_hdr)); }
1821191SN/A
1835529Snate@binkert.org    void set(const PacketPtr &ptr)
1841388SN/A    {
1851191SN/A        EthHdr *eth = (EthHdr *)ptr->data;
1865529Snate@binkert.org        if (eth->type() == ETH_TYPE_IP)
1871191SN/A            p = ptr;
1885529Snate@binkert.org        else
1891191SN/A            p = 0;
1901191SN/A    }
1915606Snate@binkert.org
1925606Snate@binkert.org  public:
1935606Snate@binkert.org    IpPtr() {}
1941191SN/A    IpPtr(const PacketPtr &ptr) { set(ptr); }
1951191SN/A    IpPtr(const EthPtr &ptr) { set(ptr.p); }
1961917SN/A    IpPtr(const IpPtr &ptr) : p(ptr.p) { }
1971917SN/A
1985529Snate@binkert.org    IpHdr *operator->() { return h(); }
1995529Snate@binkert.org    IpHdr &operator*() { return *h(); }
2001917SN/A    operator IpHdr *() { return h(); }
2015529Snate@binkert.org
2021917SN/A    const IpHdr *operator->() const { return h(); }
2031191SN/A    const IpHdr &operator*() const { return *h(); }
2041191SN/A    operator const IpHdr *() const { return h(); }
2051191SN/A
2061191SN/A    const IpPtr &operator=(const PacketPtr &ptr) { set(ptr); return *this; }
2071191SN/A    const IpPtr &operator=(const EthPtr &ptr) { set(ptr.p); return *this; }
2081191SN/A    const IpPtr &operator=(const IpPtr &ptr) { p = ptr.p; return *this; }
2091191SN/A
2101191SN/A    const PacketPtr packet() const { return p; }
2111191SN/A    PacketPtr packet() { return p; }
2121191SN/A    bool operator!() const { return !p; }
2131191SN/A    operator bool() const { return p; }
2141129SN/A    operator bool() { return p; }
2151129SN/A};
2161129SN/A
2175529Snate@binkert.orguint16_t cksum(const IpPtr &ptr);
2182680Sktlim@umich.edu
2191129SN/Astruct IpOpt : public ip_opt
220180SN/A{
2212SN/A    uint8_t type() const { return opt_type; }
2221917SN/A    uint8_t typeNumber() const { return IP_OPT_NUMBER(opt_type); }
2231917SN/A    uint8_t typeClass() const { return IP_OPT_CLASS(opt_type); }
2241917SN/A    uint8_t typeCopied() const { return IP_OPT_COPIED(opt_type); }
2255529Snate@binkert.org    uint8_t len() const { return IP_OPT_TYPEONLY(type()) ? 1 : opt_len; }
2265606Snate@binkert.org
2271917SN/A    bool isNumber(int num) const { return typeNumber() == IP_OPT_NUMBER(num); }
2282356SN/A    bool isClass(int cls) const { return typeClass() == IP_OPT_CLASS(cls); }
2295529Snate@binkert.org    bool isCopied(int cpy) const { return typeCopied() == IP_OPT_COPIED(cpy); }
2305606Snate@binkert.org
2315606Snate@binkert.org    const uint8_t *data() const { return opt_data.data8; }
2325606Snate@binkert.org    void sec(ip_opt_data_sec &sec) const;
2332356SN/A    void lsrr(ip_opt_data_rr &rr) const;
2341917SN/A    void ssrr(ip_opt_data_rr &rr) const;
2351917SN/A    void ts(ip_opt_data_ts &ts) const;
2361917SN/A    uint16_t satid() const { return ntohs(opt_data.satid); }
2371917SN/A    uint16_t mtup() const { return ntohs(opt_data.mtu); }
2382SN/A    uint16_t mtur() const { return ntohs(opt_data.mtu); }
2392SN/A    void tr(ip_opt_data_tr &tr) const;
240729SN/A    const uint32_t *addext() const { return &opt_data.addext[0]; }
241707SN/A    uint16_t rtralt() const { return ntohs(opt_data.rtralt); }
242707SN/A    void sdb(std::vector<uint32_t> &vec) const;
243707SN/A};
244707SN/A
245707SN/A/*
246707SN/A * TCP Stuff
2472680Sktlim@umich.edu */
2482SN/Astruct TcpOpt;
2492SN/Astruct TcpHdr : public tcp_hdr
2502SN/A{
2512SN/A    uint16_t sport() const { return ntohs(th_sport); }
2522680Sktlim@umich.edu    uint16_t dport() const { return ntohs(th_dport); }
2532SN/A    uint32_t seq() const { return ntohl(th_seq); }
2542SN/A    uint32_t ack() const { return ntohl(th_ack); }
2552680Sktlim@umich.edu    uint8_t  off() const { return th_off; }
2562190SN/A    uint8_t  flags() const { return th_flags & 0x3f; }
2572190SN/A    uint16_t win() const { return ntohs(th_win); }
2582190SN/A    uint16_t sum() const { return th_sum; }
2592SN/A    uint16_t urp() const { return ntohs(th_urp); }
2602SN/A
2613495Sktlim@umich.edu    void sum(uint16_t sum) { th_sum = sum; }
2623495Sktlim@umich.edu
2633495Sktlim@umich.edu    bool options(std::vector<const TcpOpt *> &vec) const;
2643661Srdreslin@umich.edu
2653495Sktlim@umich.edu    int size() const { return off(); }
2663661Srdreslin@umich.edu    const uint8_t *bytes() const { return (const uint8_t *)this; }
2673495Sktlim@umich.edu    const uint8_t *payload() const { return bytes() + size(); }
2683495Sktlim@umich.edu    uint8_t *bytes() { return (uint8_t *)this; }
2693495Sktlim@umich.edu    uint8_t *payload() { return bytes() + size(); }
2703495Sktlim@umich.edu};
2713495Sktlim@umich.edu
2723495Sktlim@umich.educlass TcpPtr
2733495Sktlim@umich.edu{
2744599Sacolyte@umich.edu  protected:
2754599Sacolyte@umich.edu    PacketPtr p;
2763661Srdreslin@umich.edu    int off;
2773495Sktlim@umich.edu
2783495Sktlim@umich.edu    const TcpHdr *h() const { return (const TcpHdr *)(p->data + off); }
2793495Sktlim@umich.edu    TcpHdr *h() { return (TcpHdr *)(p->data + off); }
2803495Sktlim@umich.edu
281180SN/A    void set(const PacketPtr &ptr, int offset) { p = ptr; off = offset; }
282180SN/A    void set(const IpPtr &ptr)
2832680Sktlim@umich.edu    {
284180SN/A        if (ptr->proto() == IP_PROTO_TCP)
2852680Sktlim@umich.edu            set(ptr.p, sizeof(eth_hdr) + ptr->hlen());
2862680Sktlim@umich.edu        else
2872378SN/A            set(0, 0);
2885714Shsul@eecs.umich.edu    }
2895713Shsul@eecs.umich.edu
2905714Shsul@eecs.umich.edu  public:
291180SN/A    TcpPtr() {}
292180SN/A    TcpPtr(const IpPtr &ptr) { set(ptr); }
293180SN/A    TcpPtr(const TcpPtr &ptr) : p(ptr.p), off(ptr.off) {}
294180SN/A
295180SN/A    TcpHdr *operator->() { return h(); }
2964000Ssaidi@eecs.umich.edu    TcpHdr &operator*() { return *h(); }
2974000Ssaidi@eecs.umich.edu    operator TcpHdr *() { return h(); }
2984000Ssaidi@eecs.umich.edu
2994000Ssaidi@eecs.umich.edu    const TcpHdr *operator->() const { return h(); }
3004000Ssaidi@eecs.umich.edu    const TcpHdr &operator*() const { return *h(); }
3014000Ssaidi@eecs.umich.edu    operator const TcpHdr *() const { return h(); }
3024000Ssaidi@eecs.umich.edu
3034000Ssaidi@eecs.umich.edu    const TcpPtr &operator=(const IpPtr &i) { set(i); return *this; }
3044000Ssaidi@eecs.umich.edu    const TcpPtr &operator=(const TcpPtr &t) { set(t.p, t.off); return *this; }
3054000Ssaidi@eecs.umich.edu
306180SN/A    const PacketPtr packet() const { return p; }
3072798Sktlim@umich.edu    PacketPtr packet() { return p; }
308180SN/A    bool operator!() const { return !p; }
3092359SN/A    operator bool() const { return p; }
3102359SN/A    operator bool() { return p; }
3112359SN/A};
3125606Snate@binkert.org
3132359SN/Auint16_t cksum(const TcpPtr &ptr);
314180SN/A
315180SN/Atypedef Range<uint16_t> SackRange;
316180SN/A
3174192Sktlim@umich.edustruct TcpOpt : public tcp_opt
318180SN/A{
3192680Sktlim@umich.edu    uint8_t type() const { return opt_type; }
320180SN/A    uint8_t len() const { return TCP_OPT_TYPEONLY(type()) ? 1 : opt_len; }
3215712Shsul@eecs.umich.edu
3225712Shsul@eecs.umich.edu    bool isopt(int opt) const { return type() == opt; }
3232680Sktlim@umich.edu
3242680Sktlim@umich.edu    const uint8_t *data() const { return opt_data.data8; }
3252680Sktlim@umich.edu
326180SN/A    uint16_t mss() const { return ntohs(opt_data.mss); }
3272680Sktlim@umich.edu    uint8_t wscale() const { return opt_data.wscale; }
3282651Ssaidi@eecs.umich.edu    bool sack(std::vector<SackRange> &vec) const;
3292680Sktlim@umich.edu    uint32_t echo() const { return ntohl(opt_data.echo); }
3302651Ssaidi@eecs.umich.edu    uint32_t tsval() const { return ntohl(opt_data.timestamp[0]); }
3315714Shsul@eecs.umich.edu    uint32_t tsecr() const { return ntohl(opt_data.timestamp[1]); }
3325714Shsul@eecs.umich.edu    uint32_t cc() const { return ntohl(opt_data.cc); }
3332359SN/A    uint8_t cksum() const{ return opt_data.cksum; }
3345217Ssaidi@eecs.umich.edu    const uint8_t *md5() const { return opt_data.md5; }
3355217Ssaidi@eecs.umich.edu
336180SN/A    int size() const { return len(); }
337605SN/A    const uint8_t *bytes() const { return (const uint8_t *)this; }
3381858SN/A    const uint8_t *payload() const { return bytes() + size(); }
3393520Sgblack@eecs.umich.edu    uint8_t *bytes() { return (uint8_t *)this; }
3402254SN/A    uint8_t *payload() { return bytes() + size(); }
3412680Sktlim@umich.edu};
3422680Sktlim@umich.edu
3432254SN/A/*
3444947Snate@binkert.org * UDP Stuff
3455606Snate@binkert.org */
346612SN/Astruct UdpHdr : public udp_hdr
3474192Sktlim@umich.edu{
3484192Sktlim@umich.edu    uint16_t sport() const { return ntohs(uh_sport); }
3494192Sktlim@umich.edu    uint16_t dport() const { return ntohs(uh_dport); }
3504192Sktlim@umich.edu    uint16_t len() const { return ntohs(uh_ulen); }
3515476Snate@binkert.org    uint16_t sum() const { return uh_sum; }
3525476Snate@binkert.org
3534192Sktlim@umich.edu    void sum(uint16_t sum) { uh_sum = sum; }
3545476Snate@binkert.org
3554192Sktlim@umich.edu    int size() const { return sizeof(udp_hdr); }
3564192Sktlim@umich.edu    const uint8_t *bytes() const { return (const uint8_t *)this; }
3575476Snate@binkert.org    const uint8_t *payload() const { return bytes() + size(); }
3585476Snate@binkert.org    uint8_t *bytes() { return (uint8_t *)this; }
3594192Sktlim@umich.edu    uint8_t *payload() { return bytes() + size(); }
3605476Snate@binkert.org};
3614192Sktlim@umich.edu
362180SN/Aclass UdpPtr
363180SN/A{
364180SN/A  protected:
3651858SN/A    PacketPtr p;
3665536Srstrong@hp.com    int off;
3675606Snate@binkert.org
3681917SN/A    const UdpHdr *h() const { return (const UdpHdr *)(p->data + off); }
3691917SN/A    UdpHdr *h() { return (UdpHdr *)(p->data + off); }
3701917SN/A
3711917SN/A    void set(const PacketPtr &ptr, int offset) { p = ptr; off = offset; }
3721917SN/A    void set(const IpPtr &ptr)
3732680Sktlim@umich.edu    {
3742680Sktlim@umich.edu        if (ptr->proto() == IP_PROTO_UDP)
3752680Sktlim@umich.edu            set(ptr.p, sizeof(eth_hdr) + ptr->hlen());
3761917SN/A        else
3772254SN/A            set(0, 0);
3785606Snate@binkert.org    }
3791917SN/A
3801917SN/A  public:
3812SN/A    UdpPtr() {}
3825704Snate@binkert.org    UdpPtr(const IpPtr &ptr) { set(ptr); }
3832SN/A    UdpPtr(const UdpPtr &ptr) : p(ptr.p), off(ptr.off) {}
3845647Sgblack@eecs.umich.edu
3852SN/A    UdpHdr *operator->() { return h(); }
3862SN/A    UdpHdr &operator*() { return *h(); }
3872SN/A    operator UdpHdr *() { return h(); }
3885704Snate@binkert.org
3892SN/A    const UdpHdr *operator->() const { return h(); }
3905647Sgblack@eecs.umich.edu    const UdpHdr &operator*() const { return *h(); }
3912SN/A    operator const UdpHdr *() const { return h(); }
3922SN/A
3932SN/A    const UdpPtr &operator=(const IpPtr &i) { set(i); return *this; }
3945704Snate@binkert.org    const UdpPtr &operator=(const UdpPtr &t) { set(t.p, t.off); return *this; }
3952SN/A
3965704Snate@binkert.org    const PacketPtr packet() const { return p; }
3972SN/A    PacketPtr packet() { return p; }
3982SN/A    bool operator!() const { return !p; }
399921SN/A    operator bool() const { return p; }
400921SN/A    operator bool() { return p; }
401921SN/A};
4024000Ssaidi@eecs.umich.edu
4035647Sgblack@eecs.umich.eduuint16_t cksum(const UdpPtr &ptr);
404921SN/A
405921SN/A/* namespace Net */ }
406921SN/A
407921SN/A#endif // __BASE_INET_HH__
408921SN/A