Source: ../../rip/packet_assembly.hh


Annotated List
Files
Globals
Hierarchy
Index
// -*- c-basic-offset: 4; tab-width: 8; indent-tabs-mode: t -*-

// Copyright (c) 2001-2003 International Computer Science Institute
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software")
// to deal in the Software without restriction, subject to the conditions
// listed in the XORP LICENSE file. These conditions include: you must
// preserve this copyright notice, and you cannot mention the copyright
// holders in advertising related to the Software without their permission.
// The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
// notice is a summary of the XORP LICENSE file; the license in that file is
// legally binding.

// $XORP: xorp/rip/packet_assembly.hh,v 1.2 2003/08/04 23:35:32 hodson Exp $

#ifndef __RIP_PACKET_ASSEMBLY_HH__
#define __RIP_PACKET_ASSEMBLY_HH__

#include "rip_module.h"
#include "libxorp/xlog.h"

#include "auth.hh"
#include "packets.hh"
#include "port.hh"

/**
 * @short Internal specialized state for PacketAssembler classes.
 *
 * Completely specialized implementations exist for IPv4 and IPv6 template
 * arguments.
 */
template <typename A>
class PacketAssemblerSpecState
{};

/**
 * @short IPv4 specialized PacketAssembler state.
 *
 * This class just holder the authentication handler that IPv4 packet
 * assembly requires.
 */
template <>
class PacketAssemblerSpecState<IPv4>
{
private:
    AuthHandlerBase& _ah;
public:
    /**
     * IPv4 Specific Constructor.
     */
    PacketAssemblerSpecState(Port<IPv4>& p)
	: _ah(*(p.af_state().auth_handler()))
    {}

    /**
     * IPv4 Specific authentication handler accessor.
     */
    inline AuthHandlerBase&	  ah()			{ return _ah; }

    /**
     * IPv4 Specific authentication handler accessor.
     */
    inline const AuthHandlerBase& ah() const		{ return _ah; }
};


/**
 * @short IPv6 specialized PacketAssembler state.
 *
 * This provides a means to query the RIP port and query the
 * configured maximum entries per packet. XXX At present it's a
 * placeholder and returns a fixed value.
 *
 * It also stores the last used nexthop value since nexthops are only
 * packed when they change.
 */
template <>
class PacketAssemblerSpecState<IPv6>
{
private:
    uint32_t _max_entries;
    IPv6     _lnh;

public:
    inline PacketAssemblerSpecState(Port<IPv6>& )
	: _max_entries(25), _lnh(IPv6::ALL_ONES())
    {}

    inline uint32_t	max_entries() const;
    inline void		reset_last_nexthop();
    inline void		set_last_nexthop(const IPv6& ip6);
    inline const IPv6&	last_nexthop() const;
};

inline uint32_t
PacketAssemblerSpecState<IPv6>::max_entries() const
{
    return _max_entries;
}

inline void
PacketAssemblerSpecState<IPv6>::reset_last_nexthop()
{
    _lnh = IPv6::ALL_ONES();
}

inline void
PacketAssemblerSpecState<IPv6>::set_last_nexthop(const IPv6& ip6)
{
    _lnh = ip6;
}

inline const IPv6&
PacketAssemblerSpecState<IPv6>::last_nexthop() const
{
    return _lnh;
}


/**
 * @short Class for RIP Response Packet Assemblers.
 *
 * Both RIPv2 and RIPng have some oddities in packing and this interface
 * provides a consistent interface for that packing.
 *
 * This class has specialized IPv4 and IPv6 implementations.
 */
template <typename A>
class ResponsePacketAssembler {
public:
    typedef A				Addr;
    typedef IPNet<A>			Net;
    typedef PacketAssemblerSpecState<A> SpState;

public:
    /**
     * Constructor.
     *
     * @param p Port to take configuration information from.
     */
    inline ResponsePacketAssembler(Port<A>& p);

    /**
     * Destructor.
     */
    inline ~ResponsePacketAssembler();

    /**
     * Start assembling RIP response packet.
     */
    inline void packet_start(RipPacket<A>* pkt);

    /**
     * Add a route to RIP response packet.
     *
     * @return true if route was added, false if packet is full and would
     * have indicated this if only @ref packet_full was called.
     */
    inline bool packet_add_route(const Net&	net,
				 const Addr&	nexthop,
				 uint16_t	cost,
				 uint16_t	tag);

    /**
     * Ready-to-go accessor.
     *
     * @return true if packet has no more space for route entries.
     */
    inline bool packet_full() const;

    /**
     * Finish packet.  Some packet types require final stage processing
     * and this method gives that processing a chance to happen.  Common
     * usage is RIPv2 authentication.
     *
     * @return true on success, false if a failure is detected.
     */
    inline bool packet_finish();

private:
    /**
     * Copy Constructor (Disabled).
     */
    ResponsePacketAssembler(const ResponsePacketAssembler&);

    /**
     * Assignment Operator (Disabled).
     */
    ResponsePacketAssembler& operator=(const ResponsePacketAssembler&);

protected:
    RipPacket<A>* _p;
    uint32_t	  _pos;
    SpState	  _sp_state;
};


/**
 * @short Class to configure a RIP packet to be a table request.
 *
 * This class has specialized IPv4 and IPv6 implementations to cater for
 * address family differences.
 */
template <typename A>
class RequestTablePacketAssembler {
public:
    typedef A				Addr;
    typedef IPNet<A>			Net;
    typedef PacketAssemblerSpecState<A> SpState;

public:
    inline RequestTablePacketAssembler(Port<A>& port) : _sp_state(port) {}

    /**
     * Take RipPacket packet and make it into a table request packet.
     *
     * @return true on success, false if an error is encountered.  Should
     * an error be encountered the reason is written to the xlog facility.
     */
    inline bool prepare(RipPacket<A>* pkt);

protected:
    SpState _sp_state;
};


// ----------------------------------------------------------------------------
// ResponsePacketAssembler<IPv4> implementation

template <>
inline
ResponsePacketAssembler<IPv4>::ResponsePacketAssembler(Port<IPv4>& p)
    : _p(0), _pos(0), _sp_state(p)
{
}

template <>
inline
ResponsePacketAssembler<IPv4>::~ResponsePacketAssembler()
{
}

template <>
inline void
ResponsePacketAssembler<IPv4>::packet_start(RipPacket<IPv4>* p)
{
    _p = p;

    const AuthHandlerBase& ah = _sp_state.ah();
    _pos = ah.head_entries();
    _p->set_max_entries(ah.head_entries() + ah.max_routing_entries());
    _p->header()->initialize(RipPacketHeader::RESPONSE,
			     RipPacketHeader::IPv4_VERSION);
}

template <>
inline bool
ResponsePacketAssembler<IPv4>::packet_full() const
{
    const AuthHandlerBase& ah = _sp_state.ah();
    return _pos == ah.max_routing_entries();
}

template <>
inline bool
ResponsePacketAssembler<IPv4>::packet_add_route(const Net&	net,
						const Addr&	nexthop,
						uint16_t	cost,
						uint16_t	tag)
{
    if (packet_full()) {
	return false;
    }
    _p->route_entry(_pos)->initialize(tag, net, nexthop, cost);
    _pos++;
    return true;
}

template <>
inline bool
ResponsePacketAssembler<IPv4>::packet_finish()
{
    vector<uint8_t> trailer;

    AuthHandlerBase& ah = _sp_state.ah();

    PacketRouteEntry<IPv4>* fe = (ah.head_entries()) ? _p->route_entry(0) : 0;

    _p->set_max_entries(_pos);
    if (ah.authenticate(_p->data_ptr(), _p->data_bytes(), fe, trailer) == 0) {
	XLOG_ERROR("Outbound authentication error: %s\n", ah.error().c_str());
	return false;
    } else if (trailer.size() != 0) {
	_p->append_data(trailer);
    }
    return true;
}

// ----------------------------------------------------------------------------
// ResponsePacketAssembler<IPv6> implementation

template <>
inline
ResponsePacketAssembler<IPv6>::ResponsePacketAssembler(Port<IPv6>& p)
    : _p(0), _pos(0), _sp_state(p)
{
}

template <>
inline
ResponsePacketAssembler<IPv6>::~ResponsePacketAssembler()
{
}

template <>
inline void
ResponsePacketAssembler<IPv6>::packet_start(RipPacket<IPv6>* p)
{
    _p = p;
    _pos = 0;
    _sp_state.reset_last_nexthop();
    _p->header()->initialize(RipPacketHeader::RESPONSE,
			     RipPacketHeader::IPv6_VERSION);
}

template <>
inline bool
ResponsePacketAssembler<IPv6>::packet_full() const
{
    return (_sp_state.max_entries() - _pos) >= 2;
}

template <>
inline bool
ResponsePacketAssembler<IPv6>::packet_add_route(const Net&	net,
						const Addr&	nexthop,
						uint16_t	cost,
						uint16_t	tag)
{
    if (packet_full()) {
	return false;
    }
    if (nexthop != _sp_state.last_nexthop()) {
	_p->route_entry(_pos)->initialize_nexthop(_sp_state.last_nexthop());
	_pos++;
	_sp_state.set_last_nexthop(nexthop);
    }
    _p->route_entry(_pos)->initialize_route(tag, net, cost);
    _pos++;
    return true;
}

template <>
inline bool
ResponsePacketAssembler<IPv6>::packet_finish()
{
    _p->set_max_entries(_pos);
    return true;
}


// ----------------------------------------------------------------------------
// RequestTablePacketAssembler<IPv4> implementation

template<>
inline bool
RequestTablePacketAssembler<IPv4>::prepare(RipPacket<IPv4>* pkt)
{
    pkt->header()->initialize(RipPacketHeader::REQUEST,
			      RipPacketHeader::IPv4_VERSION);

    AuthHandlerBase& ah = _sp_state.ah();
    pkt->set_max_entries(1 + ah.head_entries());
    pkt->route_entry(ah.head_entries())->initialize_table_request();

    vector<uint8_t> trailer;
    PacketRouteEntry<IPv4>* fe = (ah.head_entries()) ? pkt->route_entry(0) : 0;

    if (ah.authenticate(pkt->data_ptr(), pkt->data_bytes(),
			fe, trailer) == 0) {
	XLOG_ERROR("Outbound authentication error: %s\n", ah.error().c_str());
	return false;
    } else if (trailer.size() != 0) {
	pkt->append_data(trailer);
    }
    return true;
}


// ----------------------------------------------------------------------------
// RequestTablePacketAssembler<IPv6> implementation

template<>
inline bool
RequestTablePacketAssembler<IPv6>::prepare(RipPacket<IPv6>* pkt)
{
    pkt->header()->initialize(RipPacketHeader::REQUEST,
			      RipPacketHeader::IPv6_VERSION);
    pkt->set_max_entries(1);
    pkt->route_entry(0)->initialize_table_request();
    return true;
}

#endif // __RIP_PACKET_ASSEMBLY_HH__

Generated by: pavlin on possum.icir.org on Thu Aug 28 12:52:20 2003, using kdoc 2.0a54+XORP.