// -*- c-basic-offset: 4 -*-
#ifndef CLICK_FROMHOST_HH
#define CLICK_FROMHOST_HH
#include <click/element.hh>
#include <click/ipaddress.hh>
#include <click/etheraddress.hh>
#include <click/task.hh>
#include <click/notifier.hh>

CLICK_DECLS

/*
 * =title FromHost.u
 * 
 * =c
 * 
 * FromHost(DEVNAME, ADDR/MASK [, GATEWAY, HEADROOM] [, I<KEYWORDS>])
 * 
 * =s comm
 *
 * interface to /dev/tap or ethertap (user-level)
 *
 * =d
 *
 * Reads packets from and writes packets through the universal TUN/TAP
 * module in linux (the /dev/net/tun device).  This allows a
 * user-level Click to hand packets to the virtual ethernet
 * device. FromHost will also transfer packets from the virtual
 * ethernet device.
 *
 * To use this element you must have 
 * CONFIG_TUN
 * CONFIG_ETHERTAP
 * included in your kernel config (ie. the tun.o module is available).
 * Either modules or compiled in should work.
 *
 *
 * FromHost allocates a /dev/net/tun device (this might fail) and
 * runs ifconfig(8) to set the interface's local (i.e., kernel)
 * address to ADDR and the netmask to MASK. If a nonzero GATEWAY IP
 * address (which must be on the same network as the tun) is
 * specified, then FromHost tries to set up a default route through
 * that host.  HEADROOM is the number of bytes left empty before the
 * packet data (to leave room for additional encapsulation
 * headers). Default HEADROOM is 0.
 *
 * Keyword arguments are:
 *
 * =over 8
 *
 * =item ETHER
 *
 * Ethernet address. Specifies the fake device's Ethernet address. Default is
 * 00:a01:02:03:04:05.
 *
 * =back
 *
 * =n
 *
 * Linux will send ARP queries to the fake device. You must respond to these
 * queries in order to receive any IP packets, but you can obviously respond
 * with any Ethernet address you'd like. Here is one common idiom:
 *
 * tap0 :: FromHost(fake, 192.0.0.1/8)
 * -> fromhost_cl :: Classifier(12/0806, 12/0800);
 * fromhost_cl[0] -> ARPResponder(0.0.0.0/0 1:1:1:1:1:1) -> tap0;
 * fromhost_cl[1] -> ... // IP packets
 *  
 *  =e
 *
 *  FromHost(fake, 192.0.0.1/8) -> ...;
 * 
 * An error like "could not allocate a /dev/tap* device : No such file or
 * directory" usually means that you have not enabled /dev/tap* in your
 * kernel. 
 *
 * =h dev_name read-only
 * Returns the name of the device that this element is using.
 *
 * =a 
 * 
 * ToHost.u, ifconfig(8) 
 * 
 */

class FromHost : public Element { public:


    enum ConfigurePhase {
	CONFIGURE_PHASE_FROMHOST = CONFIGURE_PHASE_DEFAULT,
	CONFIGURE_PHASE_TOHOST =  CONFIGURE_PHASE_FROMHOST + 1
    };

    FromHost();
    ~FromHost();
  
    const char *class_name() const	{ return "FromHost"; }
    const char *port_count() const	{ return PORTS_0_1; }
    const char *processing() const	{ return PUSH; }

    int configure_phase() const		{ return CONFIGURE_PHASE_FROMHOST; }
    int configure(Vector<String> &, ErrorHandler *);
    int initialize(ErrorHandler *);
    void cleanup(CleanupStage);
    void add_handlers();

    void selected(int fd);

    bool run_task();
    int fd() { return _fd; }
    String dev_name() { return _dev_name; }


    static String read_param(Element *, void *);

  private:
    enum { DEFAULT_MTU = 2048 };

    int _fd;
    int _mtu_in;
    int _mtu_out;
    String _dev_name;
    IPAddress _near;
    IPAddress _mask;
    int _headroom;

    EtherAddress _macaddr;

    int try_linux_universal(ErrorHandler *);
    int try_tun(const String &, ErrorHandler *);
    int alloc_tun(ErrorHandler *);
    int setup_tun(struct in_addr near, struct in_addr mask, ErrorHandler *);
    void dealloc_tun();



    Task _task;
    NotifierSignal _nonfull_signal;

};

CLICK_ENDDECLS
#endif


syntax highlighted by Code2HTML, v. 0.9.1