// This program is free software; you can redistribute it and/or
// modify it under the terms of the BUT OPEN SOURCE LICENCE
// Version 1 as published by the Brno University of Technology, Antonínská 548/1,
// 601 90, Czech Republic.
// 
// 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.  See the
// BUT OPEN SOURCE LICENCE (BUTOSL) for more details.
// 
// You should have received a copy of the BUT OPEN SOURCE LICENCE (BUTOSL)
// along with this program; if not, write to the Brno University of Technology,
// Antonínská 548/1, 601 90, Czech Republic.

//
//
//

// UDP port 1812

#ifndef RADIUS_H
#define RADIUS_H

#include "ndwatch/ethernet.h"
#include "ndwatch/ipv4.h"
#include "ndwatch/ipv6.h"


using namespace std;

//  0                   1                   2
//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
// |     Type      |    Length     |  Value ...
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-

class Radius_Attribute
{
private:
	//Octet _type; //type is read while decoding Raduis
	Octet _len;

public:
	enum{USER_NAME=1,USER_PASSWORD=2,CHAP_PASSWORD=3,
		NAS_IP_ADDRESS=4,NAS_PORT=5,SERVICE_TYPE=6,FRAMED_PROTOCOL=7,
		FRAMED_IP_ADDRESS=8,FRAMED_IP_NETMASK=9,FRAMED_ROUTING=10,FILTER_ID=11,
		FRAMED_MTU=12,FRAMED_COMPRESSION=13,LOGIN_IP_HOST=14,LOGIN_SERVICE=15,
		LOGIN_TCP_PORT=16,REPLY_MESSAGE=18,CALLBACK_NUMBER=19,CALLBACK_ID=20,FRAMED_ROUTE=22,
		FRAMED_IPX_NETWORK=23,STATE=24,CLASS=25,VENDOR_SPECIFIC=26,SESSION_TIMEOUT=27,
		IDLE_TIMEOUT=28,TERMINATION_ACTION=29,CALLED_STATION_ID=30,CALLING_STATION_ID=31,
		NAS_IDENTIFIER=32,PROXY_STATE=33,LOGIN_LAT_SERVICE=34,LOGIN_LAT_NODE=35,LOGIN_LAT_GROUP=36,
		FRAMED_APPLETALK_LINK=37,FRAMED_APPLETALK_NETWORK=38,FRAMED_APPLETALK_ZONE=39,
		CHAP_CHALLENGE=60,NAS_PORT_TYPE=61,PORT_LIMIT=62,LOGIN_LAT_PORT=63,
		NAS_IPV6_ADDRESS=95,FRAMED_INTERFACE_ID=96,FRAMED_IPV6_PREFIX=97,
		LOGIN_IPV6_HOST=98,FRAMED_IPV6_ROUTE=99,FRAMED_IPV6_POOL=100
	};
	// there are unassigned attirbutes 17,21 in rfc!
	// 40-59 reserved for accounting!

	Radius_Attribute():_len(0){}
	virtual string name() {return "Radius_Attribute";}
	virtual Octet len(){return _len;}
	static Radius_Attribute *decode_attribute(Buffer &pkt);
	virtual bool decode(Buffer &pkt);
	virtual int type() {return 0;}
	virtual Radius_Attribute *attribute(int i) {return 0;}
	virtual ~Radius_Attribute(){}
};

class Radius_Attr_User_Name: public Radius_Attribute
{
private:
	Octet _len;
	string _user_name;
public:
	Radius_Attr_User_Name(): _len(0), _user_name("") {}
	virtual string name() {return "Radius_Attr_User_Name";}
	virtual int type() {return USER_NAME;}
	Octet len(){return _len;}
	string user_name(){return _user_name;}

	virtual bool decode(Buffer &pkt);
};


// Framed-IP-Address
//  0                   1                   2                   3
//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |     Type      |    Length     |            Address
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//          Address (cont)         |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

class Radius_Attr_Framed_IP_Address: public Radius_Attribute
{
private:
	Octet _len;
	IPv4Address _address;
public:
	Radius_Attr_Framed_IP_Address(): _len(0), _address("") {}
	virtual string name() {return "Radius_Attr_Framed_IP_Address";}
	virtual int type() {return FRAMED_IP_ADDRESS;}
	Octet len(){return _len;}
	IPv4Address *address(){return &_address;}

	virtual bool decode(Buffer &pkt);
};


// Calling-Station-Id
//  0                   1                   2
//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
// |     Type      |    Length     |  String ...
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-


class Radius_Attr_Calling_Station_Id: public Radius_Attribute
{
private:
	Octet _len;
	string _id;
public:
	Radius_Attr_Calling_Station_Id(): _len(0), _id("") {}
	virtual string name() {return "Radius_Attr_Calling_Station_Id";}
	virtual int type() {return CALLING_STATION_ID;}
	Octet len(){return _len;}
	string station_id(){return _id;}

	virtual bool decode(Buffer &pkt);
};


//0                   1                   2                   3
//0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|     Type      |    Length     |  Reserved     | Prefix-Length |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                            Prefix                             |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                            Prefix                             |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                            Prefix                             |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                            Prefix                             |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//Type
//   97 for Framed-IPv6-Prefix
//
//Length
//   At least 4 and no larger than 20.
//
//Reserved
//   This field, which is reserved and MUST be present, is always set
//   to zero.
//
//Prefix-Length
//   The length of the prefix, in bits.  At least 0 and no larger than
//   128.

class Radius_Attr_Framed_IPv6_Prefix: public Radius_Attribute
{
private:
	Octet _len;
	Octet _prefix_len;
	IPv6Address_prefix _address;
public:
	Radius_Attr_Framed_IPv6_Prefix(): _len(0),_prefix_len(0), _address() {}
	virtual string name() {return "Radius_Attr_Framed_IPv6_Prefix";}
	virtual int type() {return FRAMED_IPV6_PREFIX;}
	Octet len(){return _len;}
	IPv6Address_prefix *address(){return &_address;}

	virtual bool decode(Buffer &pkt);
};

//0                   1                   2                   3
//0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|     Type      |    Length     |             Interface-Id
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//                            Interface-Id
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//      Interface-Id             |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//
//Type
//  96 for Framed-Interface-Id
//
//Length
//  10
//
//Interface-Id
//  The Interface-Id field is 8 octets.

class Radius_Attr_Framed_Interface_Id: public Radius_Attribute
{
private:
	enum{MAX_SIZE=8};
	Octet _len;
	Octet _interface_id[MAX_SIZE];
public:
	Radius_Attr_Framed_Interface_Id(): _len(0){}
	virtual string name() {return "Radius_Attr_Framed_Interface_Id";}
	virtual int type() {return FRAMED_INTERFACE_ID;}
	Octet len(){return _len;}
	string interface_id();

	virtual bool decode(Buffer &pkt);
};

//  0                   1                   2                   3
//  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |     Code      |  Identifier   |            Length             |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |                                                               |
// |                         Authenticator                         |
// |                                                               |
// |                                                               |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// |  Attributes ...
// +-+-+-+-+-+-+-+-+-+-+-+-+-

class Radius
{
public:
	enum { MAX_OPTS = 100};
	enum { ACCESS_REQUEST=1,ACCESS_ACCEPT=2,ACCESS_REJECT=3,ACCOUNTING_REQUEST=4,ACCOUNTING_RESPONSE=5,
		ACCESS_CHALLENGE=11,STATUS_SERVER=12,STATUS_CLIENT=13};

private:
	Octet _code;
	Octet _identifier;
	Short _len;
	Octet _authenticator[16];
	int _opts_cnt;
	Radius_Attribute *_opts[MAX_OPTS];

public:
	Octet code() {return _code;}
	Octet identifier() {return _identifier;}
	Octet len() {return _len;}
	Octet *authenticator() {return _authenticator;} //make object for autentificator?
			Radius_Attribute *attribute(int i);
			bool decode(Buffer &pkt);
};

#endif //RADIUS_H
