anchor.diff:      ?LOG(Reason, T),
       ok.
   
  -%% rcv/3
  +%% handle/3
   
   %% Incoming CEA.
  -rcv('CEA' = N,
  -    #diameter_packet{header = #diameter_header{end_to_end_id = Eid,
  -                                               hop_by_hop_id = Hid}}
  -    = Pkt,
  -    #state{state = {'Wait-CEA', Hid, Eid}}
  -    = S) ->
  +handle('CEA' = N,
  +       #diameter_packet{header = #diameter_header{end_to_end_id = Eid,
  +                                                  hop_by_hop_id = Hid}}
  +       = Pkt,
  +       #state{state = {'Wait-CEA', Hid, Eid}}
  +       = S) ->
       ?LOG(recv, N),
       handle_CEA(Pkt, S);
   
   %% Incoming CER
  -rcv('CER' = N, Pkt, #state{state = recv_CER} = S) ->
  +handle('CER' = N, Pkt, #state{state = recv_CER} = S) ->
       handle_request(N, Pkt, S);
   
   %% Anything but CER/CEA in a non-Open state is an error, as is
   %% CER/CEA in anything but recv_CER/Wait-CEA.
  -rcv(Name, _, #state{state = PS})
  +handle(Name, _, #state{state = PS})
     when PS /= 'Open';
          Name == 'CER';
          Name == 'CEA' ->
       {stop, {Name, PS}};
   
  -rcv('DPR' = N, Pkt, S) ->
  +handle('DPR' = N, Pkt, S) ->
       handle_request(N, Pkt, S);
   
   %% DPA in response to DPR, with the expected identifiers.
  -rcv('DPA' = N,
  -    #diameter_packet{header = #diameter_header{end_to_end_id = Eid,
  -                                               hop_by_hop_id = Hid}
  -                            = H}
  -    = Pkt,
  +handle('DPA' = N,
  +       #diameter_packet{header = #diameter_header{end_to_end_id = Eid,
  +                                                  hop_by_hop_id = Hid}
  +                               = H}
  +       = Pkt,
       #state{dictionary = Dict0,
              transport = TPid,
              dpr = {X, Hid, Eid},
  
positive.code: 
  %% recv/2
  
  recv(#diameter_packet{header = #diameter_header{} = Hdr}
       = Pkt,
       #state{dictionary = Dict0}
       = S) ->
      recv1(diameter_codec:msg_name(Dict0, Hdr), Pkt, S);
  
  recv(#diameter_packet{header = undefined,
                        bin = Bin}
       = Pkt,
       S) ->
      recv(diameter_codec:decode_header(Bin), Pkt, S);
  
  recv(Bin, S) ->
      recv(#diameter_packet{bin = Bin}, S).
  
  %% recv1/3
  
  recv1(_,
        #diameter_packet{header = H, bin = Bin},
        #state{incoming_maxlen = M})
    when M < size(Bin) ->
      invalid(false, incoming_maxlen_exceeded, {size(Bin), H}),
      H;
  
  %% Ignore anything but an expected CER/CEA if so configured. This is
  %% non-standard behaviour.
  recv1(Name, #diameter_packet{header = H}, #state{state = {'Wait-CEA', _, _},
                                                   strict = false})
    when Name /= 'CEA' ->
      H;
  recv1(Name, #diameter_packet{header = H}, #state{state = recv_CER,
                                                   strict = false})
    when Name /= 'CER' ->
      H;
  
  %% Incoming request after outgoing DPR: discard. Don't discard DPR, so
  %% both ends don't do so when sending simultaneously.
  recv1(Name,
        #diameter_packet{header = #diameter_header{is_request = true} = H},
        #state{dpr = {_,_,_}})
    when Name /= 'DPR' ->
      invalid(false, recv_after_outgoing_dpr, H),
      H;
  
  %% Incoming request after incoming DPR: discard.
  recv1(_,
        #diameter_packet{header = #diameter_header{is_request = true} = H},
        #state{dpr = true}) ->
      invalid(false, recv_after_incoming_dpr, H),
      H;
  
  %% DPA with identifier mismatch, or in response to a DPR initiated by
  %% the service.
  recv1('DPA' = N,
        #diameter_packet{header = #diameter_header{hop_by_hop_id = Hid,
                                                   end_to_end_id = Eid}}
        = Pkt,
        #state{dpr = {X,H,E}}
        = S)
    when H /= Hid;
         E /= Eid;
         not X ->
      rcv(N, Pkt, S);
  
  %% Any other message with a header and no length errors: send to the
  %% parent.
  recv1(Name, Pkt, #state{}) ->
      {recv, Name, Pkt}.
  
  %% recv/3
  
  recv(#diameter_header{length = Len}
       = H,
       #diameter_packet{bin = Bin}
       = Pkt,
       #state{length_errors = E}
       = S)
    when E == handle;
         0 == Len rem 4, bit_size(Bin) == 8*Len ->
      recv(Pkt#diameter_packet{header = H}, S);
  
  recv(#diameter_header{}
       = H,
       #diameter_packet{bin = Bin},
       #state{length_errors = E}) ->
      T = {size(Bin), bit_size(Bin) rem 8, H},
      invalid(E, message_length_mismatch, T),
      Bin;
  
  recv(false, #diameter_packet{bin = Bin}, #state{length_errors = E}) ->
      invalid(E, truncated_header, Bin),
      Bin.
  
  %% Note that counters here only count discarded messages.
  invalid(E, Reason, T) ->
  
negative.code: %% Ignore an unsolicited DPA in particular. Note that dpa_timeout
  %% deals with the case in which the peer sends the wrong identifiers
  %% in DPA.
  handle('DPA' = N, #diameter_packet{header = H}, _) ->
      ?LOG(ignored, N),
      %% Note that these aren't counted in the normal recv counter.
      diameter_stats:incr({diameter_codec:msg_id(H), recv, ignored}),
      ok;
  
  handle(_, _, _) ->
      ok.
  
  %% incr/3
  