|
xorp
|
00001 // -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*- 00002 // vim:set sts=4 ts=8 sw=4: 00003 00004 // Copyright (c) 2001-2012 XORP, Inc and Others 00005 // 00006 // This program is free software; you can redistribute it and/or modify 00007 // it under the terms of the GNU General Public License, Version 2, June 00008 // 1991 as published by the Free Software Foundation. Redistribution 00009 // and/or modification of this program under the terms of any other 00010 // version of the GNU General Public License is not permitted. 00011 // 00012 // This program is distributed in the hope that it will be useful, but 00013 // WITHOUT ANY WARRANTY; without even the implied warranty of 00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For more details, 00015 // see the GNU General Public License, Version 2, a copy of which can be 00016 // found in the XORP LICENSE.gpl file. 00017 // 00018 // XORP Inc, 2953 Bunker Hill Lane, Suite 204, Santa Clara, CA 95054, USA; 00019 // http://xorp.net 00020 00021 // $XORP: xorp/contrib/olsr/message.hh,v 1.4 2008/10/02 21:56:34 bms Exp $ 00022 00023 #ifndef __OLSR_MESSAGE_HH__ 00024 #define __OLSR_MESSAGE_HH__ 00025 00029 class Message { 00030 public: 00031 virtual ~Message() {} 00032 00033 inline TimeVal receive_time() const 00034 { return _receive_time; } 00035 00036 inline TimeVal expiry_time() const 00037 { return _expiry_time; } 00038 00039 inline bool valid() const 00040 { return _is_valid; } 00041 00042 inline bool is_first() const 00043 { return _is_first; } 00044 00045 inline bool is_last() const 00046 { return _is_last; } 00047 00048 inline void set_is_first(bool arg) 00049 { _is_first = arg; } 00050 00051 inline void set_is_last(bool arg) 00052 { _is_last = arg; } 00053 00054 inline bool forwarded() const 00055 { return _is_forwarded; } 00056 00057 inline OlsrTypes::FaceID faceid() const 00058 { return _faceid; } 00059 00060 inline uint8_t hops() const 00061 { return _hops; } 00062 00063 inline void incr_hops() { ++_hops; } 00064 00065 inline uint16_t seqno() const 00066 { return _seqno; } 00067 00068 inline uint8_t ttl() const 00069 { return _ttl; } 00070 00071 inline void decr_ttl() { --_ttl; } 00072 00073 inline IPv4 origin() const 00074 { return _origin; } 00075 00076 inline OlsrTypes::MessageType type() const 00077 { return _type; } 00078 00079 inline void set_hop_count(uint8_t hops) 00080 { _hops = hops; } 00081 00082 inline void set_forwarded(bool is_forwarded) 00083 { _is_forwarded = is_forwarded; } 00084 00085 inline void set_expiry_time(const TimeVal& expiry_time) 00086 { _expiry_time = expiry_time; } 00087 00088 inline void set_receive_time(const TimeVal& receive_time) 00089 { _receive_time = receive_time; } 00090 00091 inline void set_seqno(uint16_t seqno) 00092 { _seqno = seqno; } 00093 00094 inline void set_ttl(uint8_t ttl) 00095 { _ttl = ttl; } 00096 00097 inline void set_type(OlsrTypes::MessageType type) 00098 { _type = type; } 00099 00100 inline void set_valid(bool is_valid) 00101 { _is_valid = is_valid; } 00102 00103 inline void set_origin(IPv4 origin) 00104 { _origin = origin; } 00105 00106 inline void set_faceid(OlsrTypes::FaceID faceid) 00107 { _faceid = faceid; } 00108 00109 virtual Message* decode(uint8_t* buf, size_t& len) 00110 throw(InvalidMessage) = 0; 00111 00112 virtual bool encode(uint8_t* buf, size_t& len) = 0; 00113 00114 virtual size_t length() const = 0; 00115 00116 virtual string str() const = 0; 00117 00118 string common_str() const; 00119 00120 /* 00121 * @return the length of the header common to all types of OLSR 00122 * protocol message. 00123 * As this varies according to the protocol family in use, it needs 00124 * to become templatized. 00125 */ 00126 static size_t get_common_header_length() { 00127 return sizeof(uint8_t) + // message type 00128 sizeof(uint8_t) + // validity time 00129 sizeof(uint16_t) + // message size (if not RA-OLSR) 00130 IPv4::addr_bytelen() + // IPv4 origin: family dependent 00131 sizeof(uint8_t) + // time-to-live 00132 sizeof(uint8_t) + // hop count 00133 sizeof(uint16_t); // message sequence number 00134 } 00135 00136 uint16_t adv_message_length() const { return _adv_message_length; } 00137 00138 protected: 00139 size_t decode_common_header(uint8_t* buf, size_t& len) 00140 throw(InvalidMessage); 00141 00142 bool encode_common_header(uint8_t* buf, size_t& len); 00143 00144 void store(uint8_t* ptr, size_t len) { 00145 _msg.resize(len); 00146 memcpy(&_msg[0], ptr, len); 00147 } 00148 00149 protected: 00150 // common message data and fields 00151 TimeVal _receive_time; // time when this message was received 00152 TimeVal _expiry_time; // this message will self destruct in 00153 // C*(1+a/16)* 2^b seconds! 00154 bool _is_valid; // this message is valid 00155 bool _is_forwarded; // this message has already been forwarded 00156 bool _is_first; // this message is the first in the packet 00157 bool _is_last; // this message is the last in the packet 00158 OlsrTypes::FaceID _faceid; // interface where this was received 00159 IPv4 _origin; // who sent it 00160 uint8_t _type; // type of message 00161 uint8_t _ttl; // time-to-live; updated when forwarded 00162 uint8_t _hops; // hop count; updated when forwarded 00163 uint16_t _seqno; // message sequence number 00164 00165 uint16_t _adv_message_length; // length field seen on wire; used by 00166 // derived class decoders. 00167 00168 vector<uint8_t> _msg; // on-wire format 00169 }; 00170 00174 class LinkCode { 00175 private: 00176 static const char* linktype_to_str(OlsrTypes::LinkType t); 00177 static const char* neighbortype_to_str(OlsrTypes::NeighborType t); 00178 public: 00179 LinkCode() : _linkcode(OlsrTypes::UNSPEC_LINK) { } 00180 00181 LinkCode(OlsrTypes::NeighborType ntype, OlsrTypes::LinkType ltype) 00182 throw(BadLinkCode) { 00183 _linkcode = ((ntype << 2) & 0x0C) | (ltype & 0x03); 00184 throw_if_not_valid(); 00185 } 00186 00187 LinkCode(uint8_t code) 00188 throw(BadLinkCode) 00189 : _linkcode(code) { 00190 throw_if_not_valid(); 00191 } 00192 00193 LinkCode(const LinkCode& rhs) 00194 : _linkcode(rhs._linkcode) 00195 {} 00196 00197 inline LinkCode& operator=(const uint8_t& rhs) 00198 throw(BadLinkCode) { 00199 _linkcode = rhs; 00200 throw_if_not_valid(); 00201 return (*this); 00202 } 00203 00204 inline operator uint8_t() const { 00205 return _linkcode; 00206 } 00207 00208 inline OlsrTypes::NeighborType neighbortype() const { 00209 return (_linkcode & 0x0C) >> 2; 00210 } 00211 00212 inline OlsrTypes::LinkType linktype() const { 00213 return _linkcode & 0x03; 00214 } 00215 00216 inline bool is_unspec_link() const { 00217 return linktype() == OlsrTypes::UNSPEC_LINK; 00218 } 00219 00220 inline bool is_asym_link() const { 00221 return linktype() == OlsrTypes::ASYM_LINK; 00222 } 00223 00224 inline bool is_sym_link() const { 00225 return linktype() == OlsrTypes::SYM_LINK; 00226 } 00227 00228 inline bool is_lost_link() const { 00229 return linktype() == OlsrTypes::LOST_LINK; 00230 } 00231 00232 inline bool is_mpr_neighbor() const { 00233 return neighbortype() == OlsrTypes::MPR_NEIGH; 00234 } 00235 00236 inline bool is_sym_neighbor() const { 00237 return neighbortype() == OlsrTypes::SYM_NEIGH; 00238 } 00239 00240 inline bool is_not_neighbor() const { 00241 return neighbortype() == OlsrTypes::NOT_NEIGH; 00242 } 00243 00244 inline string str() const { 00245 return c_format("link %s neighbor %s", 00246 linktype_to_str(linktype()), neighbortype_to_str(neighbortype())); 00247 } 00248 00249 private: 00250 inline void throw_if_not_valid() { 00251 if (!is_valid()) { 00252 xorp_throw(BadLinkCode, 00253 c_format("Bad link code: neighbor %u link %u", 00254 XORP_UINT_CAST(neighbortype()), 00255 XORP_UINT_CAST(linktype()))); 00256 } 00257 } 00258 00259 inline bool is_valid() { 00260 if (linktype() > OlsrTypes::LINKTYPE_END || 00261 neighbortype() > OlsrTypes::NEIGHBORTYPE_END || 00262 (linktype() == OlsrTypes::SYM_LINK && 00263 neighbortype() == OlsrTypes::NOT_NEIGH)) { 00264 return false; 00265 } 00266 return true; 00267 } 00268 00269 private: 00270 uint8_t _linkcode; 00271 }; 00272 00273 00279 class LinkAddrInfo { 00280 public: 00281 explicit LinkAddrInfo(const bool has_lq) 00282 : _has_etx(has_lq) 00283 {} 00284 00285 explicit LinkAddrInfo(const IPv4& addr) 00286 : _has_etx(false), _remote_addr(addr) 00287 {} 00288 00289 explicit LinkAddrInfo(const IPv4& addr, 00290 const double& near_etx, const double& far_etx) 00291 : _has_etx(true), 00292 _remote_addr(addr), 00293 _near_etx(near_etx), 00294 _far_etx(far_etx) 00295 {} 00296 #ifdef XORP_USE_USTL 00297 LinkAddrInfo() { } 00298 #endif 00299 00300 bool has_etx() const { return _has_etx; } 00301 IPv4 remote_addr() const { return _remote_addr; } 00302 double near_etx() const { return _near_etx; } 00303 double far_etx() const { return _far_etx; } 00304 00305 inline size_t size() const { 00306 size_t byte_count = IPv4::addr_bytelen(); 00307 if (has_etx()) 00308 byte_count += (sizeof(uint8_t) * 2); 00309 return byte_count; 00310 } 00311 00312 size_t copy_in(const uint8_t *from_uint8); 00313 size_t copy_out(uint8_t* to_uint8) const; 00314 00315 inline string str() const { 00316 string str = _remote_addr.str(); 00317 if (has_etx()) { 00318 str += c_format("[nq %.2f, fq %.2f]", 00319 near_etx(), 00320 far_etx()); 00321 } 00322 return str; 00323 } 00324 00325 private: 00326 bool _has_etx; 00327 IPv4 _remote_addr; 00328 00329 double _near_etx; 00330 double _far_etx; 00331 }; 00332 00336 class HelloMessage : public Message { 00337 public: 00338 typedef multimap<LinkCode, LinkAddrInfo> LinkBag; 00339 00340 public: 00341 HelloMessage() 00342 { this->set_type(OlsrTypes::HELLO_MESSAGE); } 00343 ~HelloMessage() {} 00344 00345 Message* decode(uint8_t* buf, size_t& len) throw(InvalidMessage); 00346 bool encode(uint8_t* buf, size_t& len); 00347 00348 inline size_t min_length() const { 00349 return get_common_header_length() + 00350 sizeof(uint16_t) + // reserved 00351 sizeof(uint8_t) + // Htime 00352 sizeof(uint8_t); // Willingness 00353 } 00354 00355 size_t length() const { 00356 size_t len = get_common_header_length() + 00357 sizeof(uint16_t) + // reserved 00358 sizeof(uint8_t) + // Htime 00359 sizeof(uint8_t) + // Willingness 00360 get_links_length(); 00361 return (len); 00362 } 00363 00364 inline const TimeVal get_htime() const 00365 { return _htime; } 00366 00367 inline void set_htime(const TimeVal& htime) 00368 { _htime = htime; } 00369 00370 inline OlsrTypes::WillType willingness() const 00371 { return _willingness; } 00372 00373 inline void set_willingness(OlsrTypes::WillType willingness) 00374 { _willingness = willingness; } 00375 00376 inline void add_link(const LinkCode code, const IPv4& remote_addr) { 00377 add_link(code, LinkAddrInfo(remote_addr)); 00378 } 00379 00383 size_t remove_link(const IPv4& remote_addr); 00384 00385 inline void clear() { 00386 _htime = TimeVal::ZERO(); 00387 _willingness = OlsrTypes::WILL_DEFAULT; 00388 _links.clear(); 00389 } 00390 00391 inline const LinkBag& links() const { return _links; } 00392 00396 virtual string str() const; 00397 00401 virtual size_t get_links_length() const; 00402 00403 protected: 00404 inline void add_link(const LinkCode code, 00405 const LinkAddrInfo& lai) { 00406 _links.insert(make_pair(code, lai)); 00407 } 00408 00423 virtual size_t decode_link_tuple(uint8_t* buf, size_t& len, 00424 size_t& skiplen, bool has_lq = false) 00425 throw(InvalidLinkTuple); 00426 00427 inline size_t link_tuple_header_length() const { 00428 return sizeof(uint8_t) + // link code 00429 sizeof(uint8_t) + // reserved 00430 sizeof(uint16_t); // link message size 00431 } 00432 00433 TimeVal _htime; // hello interval 00434 OlsrTypes::WillType _willingness; // willingness-to-forward 00435 LinkBag _links; // link tuples 00436 }; 00437 00441 class EtxHelloMessage : public HelloMessage { 00442 public: 00443 EtxHelloMessage() 00444 { this->set_type(OlsrTypes::LQ_HELLO_MESSAGE); } 00445 ~EtxHelloMessage() {} 00446 00447 protected: 00448 size_t decode_link_tuple(uint8_t* buf, size_t& len, 00449 size_t& skiplen, bool has_lq = true) 00450 throw(InvalidLinkTuple) 00451 { 00452 // Overriding a virtual with default arguments means the signatures 00453 // have to match. We are invoked via a pointer. 00454 return HelloMessage::decode_link_tuple(buf, len, skiplen, has_lq); 00455 } 00456 00457 inline void add_link(const LinkCode code, 00458 const IPv4& remote_addr, 00459 const double& near_etx, 00460 const double& far_etx) { 00461 HelloMessage::add_link(code, 00462 LinkAddrInfo(remote_addr, near_etx, 00463 far_etx)); 00464 } 00465 }; 00466 00470 class MidMessage : public Message { 00471 public: 00472 MidMessage() 00473 { this->set_type(OlsrTypes::MID_MESSAGE); } 00474 ~MidMessage() {} 00475 00476 Message* decode(uint8_t* buf, size_t& len) throw(InvalidMessage); 00477 00478 bool encode(uint8_t* buf, size_t& len); 00479 00480 inline size_t length() const { 00481 return get_common_header_length() + 00482 (_interfaces.size() * IPv4::addr_bytelen()); 00483 } 00484 00485 inline void add_interface(const IPv4& addr) { 00486 _interfaces.push_back(addr); 00487 } 00488 00489 inline void clear() { _interfaces.clear(); } 00490 00491 inline const vector<IPv4>& interfaces() const { return _interfaces; } 00492 00493 string str() const; 00494 00495 private: 00496 vector<IPv4> _interfaces; 00497 }; 00498 00502 class TcMessage : public Message { 00503 public: 00504 TcMessage() { this->set_type(OlsrTypes::TC_MESSAGE); } 00505 ~TcMessage() {} 00506 00507 virtual Message* decode(uint8_t* buf, size_t& len) throw(InvalidMessage); 00508 bool encode(uint8_t* buf, size_t& len); 00509 00510 inline size_t length() const { 00511 return get_common_header_length() + 00512 sizeof(uint16_t) + // ANSN 00513 sizeof(uint16_t) + // Reserved 00514 ( _neighbors.size() * sizeof(uint32_t)); // Neighbor 00515 } 00516 00517 static inline size_t min_length() { 00518 return get_common_header_length() + 00519 sizeof(uint16_t) + // ANSN 00520 sizeof(uint16_t); // Reserved 00521 } 00522 00523 inline uint16_t ansn() const { return _ansn; } 00524 inline const vector<LinkAddrInfo>& neighbors() const { 00525 return _neighbors; 00526 } 00527 00528 inline void add_neighbor(const IPv4& remote_addr) { 00529 add_neighbor(LinkAddrInfo(remote_addr)); 00530 } 00531 00532 inline size_t remove_neighbor(const IPv4& remote_addr) { 00533 size_t removed_count = 0; 00534 vector<LinkAddrInfo>::iterator ii = _neighbors.begin(); 00535 while (ii != _neighbors.end()) { 00536 if ((*ii).remote_addr() == remote_addr) { 00537 ii = _neighbors.erase(ii); 00538 ++removed_count; 00539 } else { 00540 ++ii; 00541 } 00542 } 00543 return removed_count; 00544 } 00545 00546 inline void set_ansn(uint16_t ansn) { _ansn = ansn; } 00547 00548 inline void clear() { _neighbors.clear(); _ansn = 0; } 00549 00550 inline string str() const { 00551 string str = this->common_str(); 00552 str += c_format("TC ansn %u ", XORP_UINT_CAST(ansn())); 00553 if (!_neighbors.empty()) { 00554 vector<LinkAddrInfo>::const_iterator ii; 00555 for (ii = _neighbors.begin(); ii != _neighbors.end(); ii++) 00556 str += (*ii).str() + " "; 00557 } 00558 return (str += '\n'); 00559 } 00560 00561 protected: 00562 inline void add_neighbor(const LinkAddrInfo& lai) { 00563 _neighbors.push_back(lai); 00564 } 00565 00566 void decode_tc_common(uint8_t* buf, size_t& len, bool has_lq = false) 00567 throw(InvalidMessage); 00568 00569 private: 00570 uint16_t _ansn; // advertised neighbor sequence no. 00571 vector<LinkAddrInfo> _neighbors; // advertised neighbor set. 00572 }; 00573 00577 class EtxTcMessage : public TcMessage { 00578 public: 00579 EtxTcMessage() { this->set_type(OlsrTypes::LQ_TC_MESSAGE); } 00580 ~EtxTcMessage() {} 00581 00582 inline void add_neighbor(const IPv4& remote_addr, 00583 const double& near_etx, 00584 const double& far_etx) { 00585 TcMessage::add_neighbor(LinkAddrInfo(remote_addr, near_etx, far_etx)); 00586 } 00587 00588 Message* decode(uint8_t* buf, size_t& len) throw(InvalidMessage); 00589 }; 00590 00594 class HnaMessage : public Message { 00595 public: 00596 HnaMessage() 00597 { this->set_type(OlsrTypes::HNA_MESSAGE); } 00598 ~HnaMessage() {} 00599 00600 Message* decode(uint8_t* buf, size_t& len) throw(InvalidMessage); 00601 bool encode(uint8_t* buf, size_t& len); 00602 00603 inline size_t length() const { 00604 return get_common_header_length() + 00605 (_networks.size() * 00606 (sizeof(uint32_t) + // network address 00607 sizeof(uint32_t))); // network mask 00608 } 00609 00610 inline const vector<IPv4Net>& networks() const { return _networks; } 00611 00612 inline void add_network(const IPv4Net& network) { 00613 _networks.push_back(network); 00614 } 00615 00616 inline size_t remove_network(const IPv4Net& network) { 00617 size_t removed_count = 0; 00618 vector<IPv4Net>::iterator ii = _networks.begin(); 00619 while (ii != _networks.end()) { 00620 if ((*ii) == network) { 00621 ii = _networks.erase(ii); 00622 ++removed_count; 00623 } else { 00624 ++ii; 00625 } 00626 } 00627 return removed_count; 00628 } 00629 00630 inline void clear() { _networks.clear(); } 00631 00632 inline string str() const { 00633 string str = this->common_str(); 00634 str += "HNA "; 00635 if (!_networks.empty()) { 00636 vector<IPv4Net>::const_iterator ii; 00637 for (ii = _networks.begin(); ii != _networks.end(); ii++) 00638 str += ii->str() + " "; 00639 } 00640 return (str += "\n"); 00641 } 00642 00643 private: 00644 vector<IPv4Net> _networks; 00645 }; 00646 00653 class UnknownMessage : public Message { 00654 public: 00655 Message* decode(uint8_t* buf, size_t& len) throw(InvalidMessage); 00656 00657 bool encode(uint8_t* buf, size_t& len); 00658 00659 inline size_t length() const { return _msg.size(); } 00660 00661 inline vector<uint8_t> opaque_data() { return this->_msg; } 00662 00663 inline string str() const { 00664 string str = this->common_str() + "bytes "; 00665 vector<uint8_t>::const_iterator ii; 00666 for (ii = _msg.begin(); ii != _msg.end(); ii++) 00667 str += c_format("0x%0x ", *ii); 00668 return (str += '\n'); 00669 } 00670 00671 private: 00672 size_t _opaque_data_offset; 00673 }; 00674 00684 class MessageDecoder { 00685 public: 00686 ~MessageDecoder(); 00687 00688 Message* decode(uint8_t* ptr, size_t len) throw(InvalidMessage); 00689 00690 void register_decoder(Message* message); 00691 00692 private: 00693 map<OlsrTypes::MessageType, Message* > _olsrv1; 00694 UnknownMessage _olsrv1_unknown; 00695 }; 00696 00704 class Packet { 00705 public: 00706 Packet(MessageDecoder& md, OlsrTypes::FaceID faceid = 0) 00707 : _message_decoder(md), 00708 _is_valid(false), 00709 _faceid(faceid), 00710 _seqno(0), 00711 _mtu(0) 00712 {} 00713 00714 ~Packet() {} 00715 00716 static size_t get_packet_header_length() { 00717 return sizeof(uint16_t) + // packet length 00718 sizeof(uint16_t); // packet sequence number 00719 } 00720 00724 size_t length() const; 00725 00730 size_t mtu_bound() const; 00731 00737 size_t bounded_length() const; 00738 00739 void decode(uint8_t* ptr, size_t len) throw(InvalidPacket); 00740 00749 size_t decode_packet_header(uint8_t* ptr, size_t len) 00750 throw(InvalidPacket); 00751 00755 bool encode(vector<uint8_t>& pkt); 00756 void update_encoded_seqno(vector<uint8_t>& pkt); 00757 00758 inline uint16_t seqno() const { return _seqno; } 00759 inline void set_seqno(uint16_t seqno) { _seqno = seqno; } 00760 00761 inline OlsrTypes::FaceID faceid() const 00762 { return _faceid; } 00763 00764 inline uint32_t mtu() const { return _mtu; } 00765 inline void set_mtu(const uint32_t mtu) { _mtu = mtu; } 00766 00767 inline void set_faceid(OlsrTypes::FaceID faceid) 00768 { _faceid = faceid; } 00769 00773 string str() const; 00774 00775 inline void add_message(Message* m) { 00776 _messages.push_back(m); 00777 } 00778 00779 inline void clear() { 00780 _seqno = 0; 00781 _mtu = 0; 00782 _messages.clear(); 00783 _is_valid = false; 00784 } 00785 00786 inline const vector<Message*>& messages() { return _messages; } 00787 00794 inline vector<Message*>& get_messages() { return _messages; } 00795 00796 bool valid() const { return _is_valid; } 00797 00798 vector<uint8_t>& get() { return _pkt; } 00799 00800 void store(uint8_t* ptr, size_t len) { 00801 _pkt.resize(len); 00802 memcpy(&_pkt[0], ptr, len); 00803 } 00804 00805 private: 00806 MessageDecoder& _message_decoder; 00807 bool _is_valid; 00808 OlsrTypes::FaceID _faceid; // interface where this was received 00809 uint16_t _seqno; 00810 uint32_t _mtu; // maximum transmission unit 00811 vector<Message*> _messages; // messages this packet contains. 00812 vector<uint8_t> _pkt; // on-wire packet data. 00813 }; 00814 00815 inline 00816 void 00817 initialize_message_decoder(MessageDecoder& message_decoder) 00818 { 00819 // 00820 // NOTE: Do not register UnknownMessage explicitly -- it has no 00821 // type field to match. It is deliberately used from the message 00822 // parser so that we will forward opaque messages as per the OLSR RFC. 00823 // 00824 message_decoder.register_decoder(new HelloMessage()); 00825 message_decoder.register_decoder(new TcMessage()); 00826 message_decoder.register_decoder(new MidMessage()); 00827 message_decoder.register_decoder(new HnaMessage()); 00828 #ifdef notyet 00829 message_decoder.register_decoder(new EtxHelloMessage()); 00830 message_decoder.register_decoder(new EtxTcMessage()); 00831 #endif 00832 } 00833 00834 #endif // __OLSR_MESSAGE_HH__