#  -*- text -*-
#  $Id: 0227aaff4e8f0ab39d896b3e12b1e77237ea2518 $

#######################################################################

# We check for this prefix to determine whether the class
# value was generated by this server.  It should be changed
# so that it is globally unique.
class_value_prefix = 'ai:'

#
#	Replacement for the old rlm_acct_unique module
#
#	NOTE: For compatibility with v3, the calculation of
#	Acct-Unique-Session-Id converts the input of the MD5
#	calculating to strings, and then converts the output
#	of the MD5 calculation to hex.  The result is that
#	the calculations done here will be the same as for
#	v3.
#
#	This change was necessary because in v4, the expansions
#	are binary safe.  i.e. expanding an IP address will not
#	result in the string `192.0.2.1`, but will instead be
#	represented internally as 32-bits of binary data `c0000201`.
#	The MD5 hash of those inputs will then be different.
#
#	We fix this issue by converting the MD5 inputs into printable
#	string form.
#
#	Similarly, the output of `%md5(..)` is binary safe, and is
#	therefore a binary blob.  We therefore convert the output
#	of it to a printable string via `%hex(...)`
#
acct_unique {
	#
	#  If we have a class attribute in the format
	#  'auth_id:[0-9a-f]{32}' it'll have a local value
	#  (defined by insert_acct_class), this ensures
	#  uniqueness and suitability.
	#
	#  We could just use the Class attribute as
	#  Acct-Unique-Session-Id, but this may cause problems
	#  with NAS that carry Class values across between
	#  multiple linked sessions.  So we rehash class with
	#  Acct-Session-ID to provide a truly unique session
	#  identifier.
	#
	#  Using a Class/Session-ID combination is more robust
	#  than using elements in the Accounting-Request,
	#  which may be subject to change, such as
	#  NAS-IP-Address, Net.Src.IP and
	#  NAS-Port-ID/NAS-Port.
	#
	#  This policy should ensure that session data is not
	#  affected if NAS IP addresses change, or the client
	#  roams to a different 'port' whilst maintaining its
	#  initial authentication session (Common in a
	#  wireless environment).
	#
	if ("%{Class}" =~ /${policy.class_value_prefix}([0-9a-f]{32})/i) {
		&request.Acct-Unique-Session-Id := %hex(%md5("%{1}%{Acct-Session-ID}"))
	}

	#
	#  Not All devices respect RFC 2865 when dealing with
	#  the class attribute, so be prepared to use the
	#  older style of hashing scheme if a class attribute
	#  is not included
	#
	else {
		&request.Acct-Unique-Session-Id := %hex(%md5("%{User-Name},%{Acct-Multi-Session-ID},%{Acct-Session-ID},%{&NAS-IPv6-Address || &NAS-IP-Address},%{NAS-Identifier},%{NAS-Port-ID},%{NAS-Port}"))
	}
}

#
#	Insert a (hopefully unique) value into class
#
insert_acct_class {
	&reply.Class = '${policy.class_value_prefix}' + %hex(%md5("%t%I%{Net.Src.Port}%{Net.Src.IP}%{NAS-IP-Address}%{Calling-Station-ID}%{User-Name}"))
}

#
#	Merges Acct-[Input|Output]-Octets and Acct-[Input|Output]-Gigawords into Acct-[Input|Output]-Octets64
#
#	If the &Attr-Foo doesn't exist, it's value is taken as zero.
#
acct_counters64 {
	if (!&Acct-Input-Gigawords) {
		&request.Acct-Input-Octets64 := %{&Acct-Input-Octets || 0}
	}
	else {
		&request.Acct-Input-Octets64 =  (((uint64) &Acct-Input-Gigawords) << 32) | (uint64) &Acct-Input-Octets
	}
	if (!&Acct-Output-Gigawords) {
		&request.Acct-Output-Octets64 := %{&Acct-Output-Octets || 0}
	}
	else {
		&request.Acct-Output-Octets64 = (((uint64) &Acct-Output-Gigawords) << 32) | (uint64) &Acct-Output-Octets
	}
}

