Source: ../../contrib/olsr/message.hh
|
|
|
|
// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-
// vim:set sts=4 ts=8 sw=4:
// Copyright (c) 2001-2008 XORP, Inc.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License, Version 2, June
// 1991 as published by the Free Software Foundation. Redistribution
// and/or modification of this program under the terms of any other
// version of the GNU General Public License is not permitted.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details,
// see the GNU General Public License, Version 2, a copy of which can be
// found in the XORP LICENSE.gpl file.
//
// XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA;
// http://xorp.net
// $XORP: xorp/contrib/olsr/message.hh,v 1.4 2008/10/02 21:56:34 bms Exp $
#ifndef __OLSR_MESSAGE_HH__
#define __OLSR_MESSAGE_HH__
/**
* @short An OLSR protocol message.
*/
class Message {
public:
virtual ~Message() {}
inline TimeVal receive_time() const
{ return _receive_time; }
inline TimeVal expiry_time() const
{ return _expiry_time; }
inline bool valid() const
{ return _is_valid; }
inline bool is_first() const
{ return _is_first; }
inline bool is_last() const
{ return _is_last; }
inline void set_is_first(bool arg)
{ _is_first = arg; }
inline void set_is_last(bool arg)
{ _is_last = arg; }
inline bool forwarded() const
{ return _is_forwarded; }
inline OlsrTypes::FaceID faceid() const
{ return _faceid; }
inline uint8_t hops() const
{ return _hops; }
inline void incr_hops() { ++_hops; }
inline uint16_t seqno() const
{ return _seqno; }
inline uint8_t ttl() const
{ return _ttl; }
inline void decr_ttl() { --_ttl; }
inline IPv4 origin() const
{ return _origin; }
inline OlsrTypes::MessageType type() const
{ return _type; }
inline void set_hop_count(uint8_t hops)
{ _hops = hops; }
inline void set_forwarded(bool is_forwarded)
{ _is_forwarded = is_forwarded; }
inline void set_expiry_time(const TimeVal& expiry_time)
{ _expiry_time = expiry_time; }
inline void set_receive_time(const TimeVal& receive_time)
{ _receive_time = receive_time; }
inline void set_seqno(uint16_t seqno)
{ _seqno = seqno; }
inline void set_ttl(uint8_t ttl)
{ _ttl = ttl; }
inline void set_type(OlsrTypes::MessageType type)
{ _type = type; }
inline void set_valid(bool is_valid)
{ _is_valid = is_valid; }
inline void set_origin(IPv4 origin)
{ _origin = origin; }
inline void set_faceid(OlsrTypes::FaceID faceid)
{ _faceid = faceid; }
virtual Message* decode(uint8_t* buf, size_t& len)
throw(InvalidMessage) = 0;
virtual bool encode(uint8_t* buf, size_t& len) = 0;
virtual size_t length() const = 0;
virtual string str() const = 0;
string common_str() const;
/*
* @return the length of the header common to all types of OLSR
* protocol message.
* As this varies according to the protocol family in use, it needs
* to become templatized.
*/
static size_t get_common_header_length() {
return sizeof(uint8_t) + // message type
sizeof(uint8_t) + // validity time
sizeof(uint16_t) + // message size (if not RA-OLSR)
IPv4::addr_bytelen() + // IPv4 origin: family dependent
sizeof(uint8_t) + // time-to-live
sizeof(uint8_t) + // hop count
sizeof(uint16_t); // message sequence number
}
uint16_t adv_message_length() const { return _adv_message_length; }
protected:
size_t decode_common_header(uint8_t* buf, size_t& len)
throw(InvalidMessage);
bool encode_common_header(uint8_t* buf, size_t& len);
void store(uint8_t* ptr, size_t len) {
_msg.resize(len);
memcpy(&_msg[0], ptr, len);
}
protected:
// common message data and fields
TimeVal _receive_time; // time when this message was received
TimeVal _expiry_time; // this message will self destruct in
// C*(1+a/16)* 2^b seconds!
bool _is_valid; // this message is valid
bool _is_forwarded; // this message has already been forwarded
bool _is_first; // this message is the first in the packet
bool _is_last; // this message is the last in the packet
OlsrTypes::FaceID _faceid; // interface where this was received
IPv4 _origin; // who sent it
uint8_t _type; // type of message
uint8_t _ttl; // time-to-live; updated when forwarded
uint8_t _hops; // hop count; updated when forwarded
uint16_t _seqno; // message sequence number
uint16_t _adv_message_length; // length field seen on wire; used by
// derived class decoders.
vector<uint8_t> _msg; // on-wire format
};
/**
* @short Helper class which represents the link code used in a link tuple.
*/
class LinkCode {
private:
static const char* linktype_to_str(OlsrTypes::LinkType t);
static const char* neighbortype_to_str(OlsrTypes::NeighborType t);
public:
LinkCode() {}
LinkCode(OlsrTypes::NeighborType ntype, OlsrTypes::LinkType ltype)
throw(BadLinkCode) {
_linkcode = ((ntype << 2) & 0x0C) | (ltype & 0x03);
throw_if_not_valid();
}
LinkCode(uint8_t code)
throw(BadLinkCode)
: _linkcode(code) {
throw_if_not_valid();
}
LinkCode(const LinkCode& rhs)
: _linkcode(rhs._linkcode)
{}
inline LinkCode& operator=(const uint8_t& rhs)
throw(BadLinkCode) {
_linkcode = rhs;
throw_if_not_valid();
return (*this);
}
inline operator uint8_t() const {
return _linkcode;
}
inline OlsrTypes::NeighborType neighbortype() const {
return (_linkcode & 0x0C) >> 2;
}
inline OlsrTypes::LinkType linktype() const {
return _linkcode & 0x03;
}
inline bool is_unspec_link() const {
return linktype() == OlsrTypes::UNSPEC_LINK;
}
inline bool is_asym_link() const {
return linktype() == OlsrTypes::ASYM_LINK;
}
inline bool is_sym_link() const {
return linktype() == OlsrTypes::SYM_LINK;
}
inline bool is_lost_link() const {
return linktype() == OlsrTypes::LOST_LINK;
}
inline bool is_mpr_neighbor() const {
return neighbortype() == OlsrTypes::MPR_NEIGH;
}
inline bool is_sym_neighbor() const {
return neighbortype() == OlsrTypes::SYM_NEIGH;
}
inline bool is_not_neighbor() const {
return neighbortype() == OlsrTypes::NOT_NEIGH;
}
inline string str() const {
return c_format("link %s neighbor %s",
linktype_to_str(linktype()), neighbortype_to_str(neighbortype()));
}
private:
inline void throw_if_not_valid() {
if (!is_valid()) {
xorp_throw(BadLinkCode,
c_format("Bad link code: neighbor %u link %u",
XORP_UINT_CAST(neighbortype()),
XORP_UINT_CAST(linktype())));
}
}
inline bool is_valid() {
if (linktype() > OlsrTypes::LINKTYPE_END ||
neighbortype() > OlsrTypes::NEIGHBORTYPE_END ||
(linktype() == OlsrTypes::SYM_LINK &&
neighbortype() == OlsrTypes::NOT_NEIGH)) {
return false;
}
return true;
}
private:
uint8_t _linkcode;
};
/**
* @short Wrapper for per-address information found in HELLO and TC.
*
* This is space-pessimized for the case where ETX measurements are in use.
*/
class LinkAddrInfo {
public:
explicit LinkAddrInfo(const bool has_lq)
: _has_etx(has_lq)
{}
explicit LinkAddrInfo(const IPv4& addr)
: _has_etx(false), _remote_addr(addr)
{}
explicit LinkAddrInfo(const IPv4& addr,
const double& near_etx, const double& far_etx)
: _has_etx(true),
_remote_addr(addr),
_near_etx(near_etx),
_far_etx(far_etx)
{}
bool has_etx() const { return _has_etx; }
IPv4 remote_addr() const { return _remote_addr; }
double near_etx() const { return _near_etx; }
double far_etx() const { return _far_etx; }
inline size_t size() const {
size_t byte_count = IPv4::addr_bytelen();
if (has_etx())
byte_count += (sizeof(uint8_t) * 2);
return byte_count;
}
size_t copy_in(const uint8_t *from_uint8);
size_t copy_out(uint8_t* to_uint8) const;
inline string str() const {
string str = _remote_addr.str();
if (has_etx()) {
str += c_format("[nq %.2f, fq %.2f]",
near_etx(),
far_etx());
}
return str;
}
private:
bool _has_etx;
IPv4 _remote_addr;
double _near_etx;
double _far_etx;
};
/**
* @short Representation of a HELLO protocol message.
*/
class HelloMessage : public Message {
public:
typedef multimap<LinkCode, LinkAddrInfo> LinkBag;
public:
HelloMessage()
{ this->set_type(OlsrTypes::HELLO_MESSAGE); }
~HelloMessage() {}
Message* decode(uint8_t* buf, size_t& len) throw(InvalidMessage);
bool encode(uint8_t* buf, size_t& len);
inline size_t min_length() const {
return get_common_header_length() +
sizeof(uint16_t) + // reserved
sizeof(uint8_t) + // Htime
sizeof(uint8_t); // Willingness
}
size_t length() const {
size_t len = get_common_header_length() +
sizeof(uint16_t) + // reserved
sizeof(uint8_t) + // Htime
sizeof(uint8_t) + // Willingness
get_links_length();
return (len);
}
inline const TimeVal get_htime() const
{ return _htime; }
inline void set_htime(const TimeVal& htime)
{ _htime = htime; }
inline OlsrTypes::WillType willingness() const
{ return _willingness; }
inline void set_willingness(OlsrTypes::WillType willingness)
{ _willingness = willingness; }
inline void add_link(const LinkCode code, const IPv4& remote_addr) {
add_link(code, LinkAddrInfo(remote_addr));
}
/**
* Remove a given neighbor interface address from ALL link tuples.
*/
size_t remove_link(const IPv4& remote_addr);
inline void clear() {
_htime = TimeVal::ZERO();
_willingness = OlsrTypes::WILL_DEFAULT;
_links.clear();
}
inline const LinkBag& links() const { return _links; }
/**
* Print a HelloMessage as a string.
*/
virtual string str() const;
/**
* Calculate the on-wire size of all link state tuples.
*/
virtual size_t get_links_length() const;
protected:
inline void add_link(const LinkCode code,
const LinkAddrInfo& lai) {
_links.insert(make_pair(code, lai));
}
/**
* Decode a single link tuple from the buffer into the HelloMessage.
*
* @param buf pointer to the buffer to decode.
* @param len the number of bytes in the buffer.
* @param skiplen the number of bytes consumed by this function.
* @param has_lq true if this function is being called from derived
* class EtxHelloMessage to process ETX information,
* otherwise false.
* @return the number of bytes consumed in the input stream to produce
* a decoded link tuple.
* @throw InvalidLinkTuple if an invalid link tuple was found
* during message decoding.
*/
virtual size_t decode_link_tuple(uint8_t* buf, size_t& len,
size_t& skiplen, bool has_lq = false)
throw(InvalidLinkTuple);
inline size_t link_tuple_header_length() const {
return sizeof(uint8_t) + // link code
sizeof(uint8_t) + // reserved
sizeof(uint16_t); // link message size
}
TimeVal _htime; // hello interval
OlsrTypes::WillType _willingness; // willingness-to-forward
LinkBag _links; // link tuples
};
/**
* @short Specialization of a HELLO message with ETX measurements.
*/
class EtxHelloMessage : public HelloMessage {
public:
EtxHelloMessage()
{ this->set_type(OlsrTypes::LQ_HELLO_MESSAGE); }
~EtxHelloMessage() {}
protected:
size_t decode_link_tuple(uint8_t* buf, size_t& len,
size_t& skiplen, bool has_lq = true)
throw(InvalidLinkTuple)
{
// Overriding a virtual with default arguments means the signatures
// have to match. We are invoked via a pointer.
return HelloMessage::decode_link_tuple(buf, len, skiplen, has_lq);
}
inline void add_link(const LinkCode code,
const IPv4& remote_addr,
const double& near_etx,
const double& far_etx) {
HelloMessage::add_link(code,
LinkAddrInfo(remote_addr, near_etx,
far_etx));
}
};
/**
* @short Representation of a MID protocol message.
*/
class MidMessage : public Message {
public:
MidMessage()
{ this->set_type(OlsrTypes::MID_MESSAGE); }
~MidMessage() {}
Message* decode(uint8_t* buf, size_t& len) throw(InvalidMessage);
bool encode(uint8_t* buf, size_t& len);
inline size_t length() const {
return get_common_header_length() +
(_interfaces.size() * IPv4::addr_bytelen());
}
inline void add_interface(const IPv4& addr) {
_interfaces.push_back(addr);
}
inline void clear() { _interfaces.clear(); }
inline const vector<IPv4>& interfaces() const { return _interfaces; }
string str() const;
private:
vector<IPv4> _interfaces;
};
/**
* @short Representation of a TC protocol message.
*/
class TcMessage : public Message {
public:
TcMessage() { this->set_type(OlsrTypes::TC_MESSAGE); }
~TcMessage() {}
virtual Message* decode(uint8_t* buf, size_t& len) throw(InvalidMessage);
bool encode(uint8_t* buf, size_t& len);
inline size_t length() const {
return get_common_header_length() +
sizeof(uint16_t) + // ANSN
sizeof(uint16_t) + // Reserved
( _neighbors.size() * sizeof(uint32_t)); // Neighbor
}
static inline size_t min_length() {
return get_common_header_length() +
sizeof(uint16_t) + // ANSN
sizeof(uint16_t); // Reserved
}
inline uint16_t ansn() const { return _ansn; }
inline const vector<LinkAddrInfo>& neighbors() const {
return _neighbors;
}
inline void add_neighbor(const IPv4& remote_addr) {
add_neighbor(LinkAddrInfo(remote_addr));
}
inline size_t remove_neighbor(const IPv4& remote_addr) {
size_t removed_count = 0;
vector<LinkAddrInfo>::iterator ii = _neighbors.begin();
while (ii != _neighbors.end()) {
if ((*ii).remote_addr() == remote_addr) {
ii = _neighbors.erase(ii);
++removed_count;
} else {
++ii;
}
}
return removed_count;
}
inline void set_ansn(uint16_t ansn) { _ansn = ansn; }
inline void clear() { _neighbors.clear(); _ansn = 0; }
inline string str() const {
string str = this->common_str();
str += c_format("TC ansn %u ", XORP_UINT_CAST(ansn()));
if (!_neighbors.empty()) {
vector<LinkAddrInfo>::const_iterator ii;
for (ii = _neighbors.begin(); ii != _neighbors.end(); ii++)
str += (*ii).str() + " ";
}
return (str += '\n');
}
protected:
inline void add_neighbor(const LinkAddrInfo& lai) {
_neighbors.push_back(lai);
}
void decode_tc_common(uint8_t* buf, size_t& len, bool has_lq = false)
throw(InvalidMessage);
private:
uint16_t _ansn; // advertised neighbor sequence no.
vector<LinkAddrInfo> _neighbors; // advertised neighbor set.
};
/**
* @short Specialization of a TC message with ETX measurements.
*/
class EtxTcMessage : public TcMessage {
public:
EtxTcMessage() { this->set_type(OlsrTypes::LQ_TC_MESSAGE); }
~EtxTcMessage() {}
inline void add_neighbor(const IPv4& remote_addr,
const double& near_etx,
const double& far_etx) {
TcMessage::add_neighbor(LinkAddrInfo(remote_addr, near_etx, far_etx));
}
Message* decode(uint8_t* buf, size_t& len) throw(InvalidMessage);
};
/**
* @short Representation of an HNA message, containing external routes.
*/
class HnaMessage : public Message {
public:
HnaMessage()
{ this->set_type(OlsrTypes::HNA_MESSAGE); }
~HnaMessage() {}
Message* decode(uint8_t* buf, size_t& len) throw(InvalidMessage);
bool encode(uint8_t* buf, size_t& len);
inline size_t length() const {
return get_common_header_length() +
(_networks.size() *
(sizeof(uint32_t) + // network address
sizeof(uint32_t))); // network mask
}
inline const vector<IPv4Net>& networks() const { return _networks; }
inline void add_network(const IPv4Net& network) {
_networks.push_back(network);
}
inline size_t remove_network(const IPv4Net& network) {
size_t removed_count = 0;
vector<IPv4Net>::iterator ii = _networks.begin();
while (ii != _networks.end()) {
if ((*ii) == network) {
ii = _networks.erase(ii);
++removed_count;
} else {
++ii;
}
}
return removed_count;
}
inline void clear() { _networks.clear(); }
inline string str() const {
string str = this->common_str();
str += "HNA ";
if (!_networks.empty()) {
vector<IPv4Net>::const_iterator ii;
for (ii = _networks.begin(); ii != _networks.end(); ii++)
str += ii->str() + " ";
}
return (str += "\n");
}
private:
vector<IPv4Net> _networks;
};
/**
* @short Wrapper class for an unknown OLSR message type.
*
* Used for passing messages to entities which need to deal with them
* in an opaque way, e.g. Secured OLSR.
*/
class UnknownMessage : public Message {
public:
Message* decode(uint8_t* buf, size_t& len) throw(InvalidMessage);
bool encode(uint8_t* buf, size_t& len);
inline size_t length() const { return _msg.size(); }
inline vector<uint8_t> opaque_data() { return this->_msg; }
inline string str() const {
string str = this->common_str() + "bytes ";
vector<uint8_t>::const_iterator ii;
for (ii = _msg.begin(); ii != _msg.end(); ii++)
str += c_format("0x%0x ", *ii);
return (str += '\n');
}
private:
size_t _opaque_data_offset;
};
/**
* @short Decoder for OLSR protocol messages.
*
* Empty messages are registered with this class in a producer/consumer
* pattern. When adding a new message class, make sure in its decode()
* method that you are storing the message properties in the message
* you've created -- not the fields of the empty message registered
* with this class.
*/
class MessageDecoder {
public:
~MessageDecoder();
Message* decode(uint8_t* ptr, size_t len) throw(InvalidMessage);
void register_decoder(Message* message);
private:
map<OlsrTypes::MessageType, Message* > _olsrv1;
UnknownMessage _olsrv1_unknown;
};
/**
* @short An OLSR packet containing Messages.
*
* Packets contain Messages. They are coalesced up up to the available
* MTU size, to save power on devices where transmission may have a high
* energy cost.
*/
class Packet {
public:
Packet(MessageDecoder& md, OlsrTypes::FaceID faceid = 0)
: _message_decoder(md),
_is_valid(false),
_faceid(faceid),
_seqno(0),
_mtu(0)
{}
~Packet() {}
static size_t get_packet_header_length() {
return sizeof(uint16_t) + // packet length
sizeof(uint16_t); // packet sequence number
}
/**
* @return the size of the packet payload.
*/
size_t length() const;
/**
* @return the amount of free space in this packet for an OLSR
* packet payload, after MTU is taken into account.
*/
size_t mtu_bound() const;
/**
* @return the size of the packet payload which will fit inside
* the MTU without splitting any messages.
* If no MTU is set, returns length().
*/
size_t bounded_length() const;
void decode(uint8_t* ptr, size_t len) throw(InvalidPacket);
/**
* Decode an OLSR packet header.
*
* An OLSR packet is considered valid if its length is greater than
* the size of a standard packet header.
* The host IP stack takes care of UDP checksums, IP fragmentation and
* reassembly, and MTU size checks for us.
*/
size_t decode_packet_header(uint8_t* ptr, size_t len)
throw(InvalidPacket);
/**
* Encode a packet, including any nested messages.
*/
bool encode(vector<uint8_t>& pkt);
void update_encoded_seqno(vector<uint8_t>& pkt);
inline uint16_t seqno() const { return _seqno; }
inline void set_seqno(uint16_t seqno) { _seqno = seqno; }
inline OlsrTypes::FaceID faceid() const
{ return _faceid; }
inline uint32_t mtu() const { return _mtu; }
inline void set_mtu(const uint32_t mtu) { _mtu = mtu; }
inline void set_faceid(OlsrTypes::FaceID faceid)
{ _faceid = faceid; }
/**
* @return a string representation of the entire packet.
*/
string str() const;
inline void add_message(Message* m) {
_messages.push_back(m);
}
inline void clear() {
_seqno = 0;
_mtu = 0;
_messages.clear();
_is_valid = false;
}
inline const vector<Message*>& messages() { return _messages; }
/**
* Get a non-const reference to a packet's messages.
* For debugging use only, ie in simulation of multiple hops.
*
* @return reference to the messages contained within the packet.
*/
inline vector<Message*>& get_messages() { return _messages; }
bool valid() const { return _is_valid; }
vector<uint8_t>& get() { return _pkt; }
void store(uint8_t* ptr, size_t len) {
_pkt.resize(len);
memcpy(&_pkt[0], ptr, len);
}
private:
MessageDecoder& _message_decoder;
bool _is_valid;
OlsrTypes::FaceID _faceid; // interface where this was received
uint16_t _seqno;
uint32_t _mtu; // maximum transmission unit
vector<Message*> _messages; // messages this packet contains.
vector<uint8_t> _pkt; // on-wire packet data.
};
inline
void
initialize_message_decoder(MessageDecoder& message_decoder)
{
//
// NOTE: Do not register UnknownMessage explicitly -- it has no
// type field to match. It is deliberately used from the message
// parser so that we will forward opaque messages as per the OLSR RFC.
//
message_decoder.register_decoder(new HelloMessage());
message_decoder.register_decoder(new TcMessage());
message_decoder.register_decoder(new MidMessage());
message_decoder.register_decoder(new HnaMessage());
#ifdef notyet
message_decoder.register_decoder(new EtxHelloMessage());
message_decoder.register_decoder(new EtxTcMessage());
#endif
}
#endif // __OLSR_MESSAGE_HH__
Generated by: pavlin on kobe.xorp.net on Wed Dec 24 16:29:24 2008, using kdoc 2.0a54+XORP.