anchor.diff:  %% @hidden
   request(ServiceName, Capabilities, Request, [H | T]) ->
   	case ocs:find_client(H) of
  -		{ok, #client{protocol = diameter, port = Port,
  -				password_required = PasswordReq, trusted = Trusted}} ->
  -			process_request(ServiceName, Capabilities, Request,
  -					H, Port, PasswordReq, Trusted);
  +		{ok, #client{protocol = diameter}} ->
  +			process_request(ServiceName, Capabilities, Request);
   		{error, not_found} ->
   			request(ServiceName, Capabilities, Request, T)
   	end;
  
positive.code: 			[?'DIAMETER_BASE_RESULT-CODE_UNKNOWN_PEER']),
  	{answer_message, Error}.
  
  -spec process_request(ServiceName, Capabilities, Request,
  		Address, Port, PasswordReq, Trusted) -> Result
  	when
  		ServiceName :: term(),
  		Capabilities :: capabilities(),
  		Request :: term(),
  		Address :: inet:ip_address(),
  		Port :: inet:port(),
  		PasswordReq :: boolean(),
  		Trusted :: boolean(),
  		Result :: {reply, packet()} | discard.
  %% @doc Process a received DIAMETER packet.
  %% @private
  %% @todo Handle S6a/S6d requests.
  process_request(ServiceName, _Capabilities, Request,
  		Address, Port, PasswordReq, Trusted) ->
  erlang:display({?MODULE, ?LINE, Request}), discard;
  process_request(ServiceName, #diameter_caps{origin_host = {OHost, _DHost},
  		origin_realm = {ORealm, _DRealm}} = Capabilities,
  		#'3gpp_s6a_AIR'{'Session-Id' = SId} = Request,
  		Address, Port, PasswordReq, Trusted) ->
  	try
  		process_request1(ServiceName, Capabilities,
  				Request, Address, Port, PasswordReq, Trusted)
  	catch
  		_:_Reason ->
  			{reply, #'3gpp_s6a_AIA'{'Session-Id' = SId,
  					'Result-Code' = ?'DIAMETER_BASE_RESULT-CODE_INVALID_AVP_BITS',
  					'Origin-Host' = OHost, 'Origin-Realm' = ORealm}}
  	end.
  %% @hidden
  process_request1(ServiceName, Capabilities,
  		Request, Address, Port, PasswordReq, Trusted) ->
  	[Info] = diameter:service_info(ServiceName, transport),
  	case lists:keyfind(options, 1, Info) of
  		{options, Options} ->
  			case lists:keyfind(transport_config, 1, Options) of
  				{transport_config, TC} ->
  					{ip, Sip} = lists:keyfind(ip, 1, TC),
  					{port, Sport} = lists:keyfind(port, 1, TC),
  					case global:whereis_name({ocs_diameter_auth, Sip, Sport}) of
  						undefined ->
  							discard;
  						PortServer ->
  							Answer = gen_server:call(PortServer,
  									{diameter_request, Capabilities,
  											Address, Port, PasswordReq, Trusted,
  											Request, none}),
  							{reply, Answer}
  					end;
  				false ->
  					discard
  			end;
  		false ->
  			discard
  	end.
  
  -spec errors(ServiceName, Capabilities, Request, Errors) -> Result
  	when
  
negative.code: errors(_ServiceName, _Capabilities, _Request, []) ->
  	ok.
  
  -spec sqn(DIF) -> SQN
  	when
  		DIF :: integer(),
  		SQN :: integer().
  %% @doc Sequence Number (SQN).
  %%
  %% 	3GPP RTS 33.102 Annex C.1.1.3.
  %% @private
  sqn(DIF) when is_integer(DIF) ->
  	(erlang:system_time(10) + DIF) bsl 5.
  
  -spec autn(SQN, AK, AMF, MAC) -> AUTN
  	when
  		SQN :: integer(),
  		AK :: integer(),
  		AMF :: binary(),
  		MAC :: binary(),
  		AUTN :: binary().
  %% @doc Network Authentication Token (AUTN).
  %%
  %% @private
  autn(SQN, AK, AMF, MAC)
  		when is_integer(SQN), is_integer(AK),
  		byte_size(AMF) =:= 2, byte_size(MAC) =:= 8 ->
  	SQNa = SQN bxor AK,
  	<<SQNa:48, AMF/binary, MAC/binary>>.
  
  -spec sqn_ms(SQN, OPc, K, RAND) -> SQN
  	when
  		SQN:: integer(),
  		OPc :: binary(),
  		K :: binary(),
  		RAND :: binary(),
  		SQN :: integer().
  %% @doc Retrieve concealed `SQNms' from AUTS.
  %%
  %% @private
  sqn_ms(SQN, OPc, K, RAND)
  		when is_integer(SQN), byte_size(OPc) =:= 16,
  		byte_size(K) =:= 16, byte_size(RAND) =:= 16 ->
  	<<AK:48>> = ocs_milenage:'f5*'(OPc, K, RAND),
  	SQN bxor AK.
  
  -spec dif(SQN) -> DIF
  	when
  		SQN :: integer(),
  		DIF :: integer().
  %% @doc The DIF value represents the current difference
  %% 	between generated SEQ values for that user and the GLC.
  %%
  %% 	3GPP RTS 33.102 Annex C.1.1.3.
  %% @private
  dif(SQN) when is_integer(SQN) ->
  	SEQ = SQN bsr 5,
  	SEQ - erlang:system_time(10).
  
  -spec kdf(CK, IK, SN, SQN, AK) -> MSK
  	when
  		CK :: binary(),
  		IK :: binary(),
  		SN :: binary(),
  		SQN :: integer(),
  		AK :: integer(),
  		MSK :: binary().
  %% @doc Key Derivation Function (KDF).
  %%
  %% 	See 3GPP TS 33.402 Annex A,
  %% 	    3GPP TS 32.220 Annex B.
  %% @private
  kdf(CK, IK, SN, SQN, AK)
  		when byte_size(CK) =:= 16,
  		byte_size(IK) =:= 16,
  		((byte_size(SN) =:= 3) or (byte_size(SN) =:= 2)),
  		is_integer(SQN), is_integer(AK) ->
  	FC = 16#10,
  	P0 = SN,
  	L0 = byte_size(SN),
  	P1 = SQN bxor AK,
  	L1 = 6,
  	crypto:hmac(sha256, <<CK/binary, IK/binary>>,
  			<<FC, P0/bytes, L0:16, P1:48, L1:16>>).
  
  -spec save_dif(IMSI, DIF) -> ok
  	when
  		IMSI :: binary(),
  		DIF :: integer().
  %% @doc Save the new DIF for subscriber.
  %% @hidden
  save_dif(IMSI, DIF)
  		when is_binary(IMSI), is_integer(DIF)->
  	Now = erlang:system_time(?MILLISECOND),
  	N = erlang:unique_integer([positive]),
  	LM = {Now, N},
  	F = fun() ->
  			[#service{password = P} = S1] = mnesia:read(service, IMSI, write),
  			S2 = S1#service{last_modified = LM,
  					password = P#aka_cred{dif  = DIF}},
  			mnesia:write(service, S2, write)
  	end,
  	case mnesia:transaction(F) of
  		{atomic, ok} ->
  			ok;
  		{aborted, Reason} ->
  			exit(Reason)
  	end.
  
  