/*
** pat_seqack.c for  in 
** 
** Made by 
** Login   <vianney@epita.fr>
** 
** Started on  Wed Sep  1 06:41:31 1999 
** Last update Thu Oct 28 20:19:39 1999 
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "pat_seqack.h"
#include "pat_tcp.h"

#define SEQ_ACK_HASHSIZE	919

t_seq_ack_hash			seq_ack_hash[SEQ_ACK_HASHSIZE];

int	seqack_chan;

PAT_NAME_GENERIC(seqack_pat_name,
		 (VOID_PTR)&seqack_chan,
		 "seqack")

PAT_EXTRACT_DECL(seqack_pat_extract)
{
  t_seq_ack		*sa;
  t_tcp_seq		seq;
  t_tcp_seq		ack;
  t_status		status;

  if (len < sizeof (t_seq_ack))
    return (ERR_PAT_TRUNC_FIELD);
  sa = (t_seq_ack *)(buf);
  seq = safe_ntohl(&sa->seq); /* alignment */
  ack = safe_ntohl(&sa->ack); /* alignment */
  if (data)
    {
      t_seq_ack_data	*sad;
      t_seq_ack_key	sak;
      t_boolean		rev;
      t_seq_ack_hash	*sah;
      
      sad = (t_seq_ack_data *)(data);
      if (sad->sport < sad->dport ||
	  (sad->sport == sad->dport &&
	   sad->src.addr < sad->dst.addr)) 
	{
	  FBCOPY(&sad->src,&sak.src,sizeof (sak.src));
	  FBCOPY(&sad->dst,&sak.dst,sizeof (sak.dst));
	  sak.port = sad->sport << 16 | sad->dport;
	  rev = FALSE;
	}
      else 
	{
	  FBCOPY(&sad->dst,&sak.src,sizeof (sak.src));
	  FBCOPY(&sad->src,&sak.dst,sizeof (sak.dst));
	  sak.port = sad->dport << 16 | sad->sport;
	  rev = TRUE;
	}
      for (sah = &seq_ack_hash[sak.port % SEQ_ACK_HASHSIZE];
	   sah->next;
	   sah = sah->next)
	if (!FBCMP(&sak,&sah->key,sizeof (sah->key)))
	  break;
      if (sah->next)
	{
	  if (sah->ack == ack &&
	      sah->seq == seq)
	    goto unchanged;
	  if (sad->flags & TCP_SYN)
	    goto new;
	  if (rev)
	    {
	      seq -= sah->ack;
	      ack -= sah->seq;
	    }
	  else
	    {
	      seq -= sah->seq;
	      ack -= sah->ack;
	    }
	}
      else
	{
	new:
	  if (sah->next == NULL) 
	    {
	      if ((sah->next = PAT_ALLOC_PROC(sizeof (t_seq_ack_hash),
					      "pat",
					      "pat_seqack_msg:ptr",
					      &status)) == NULL)
		return (status);
	      FBZERO(sah->next,sizeof (t_seq_ack_hash));
	    }
	  FBCOPY(&sak,&sah->key,sizeof (t_seq_ack_key));
	  if (rev)
	    {
	      sah->ack = seq;
	      sah->seq = ack - 1;
	    }
	  else
	    {
	      sah->seq = seq;
	      sah->ack = ack - 1;
	    }
	}
    unchanged:
      if (sad->seq_wanted)
	return (str_cat_fmt_va(str,
			       max_len,
			       "%d:%d(%d)",
			       seq,
			       seq + sad->datalen,
			       sad->datalen));
      else
	return (ulong_to_str((unsigned long)ack,
			     pat_base,
			     str,
			     max_len));
    }
  return (0);
}

PAT_INSERT_DECL(seqack_pat_insert)
{
  return (ERR_PAT_NI);
}

PAT_OFF_GENERIC(seqack_pat_off,
		sizeof (t_seq_ack))

t_pat				seqack_pat = 
{
  seqack_pat_name,		/* t_pat_name_proc		*/
  seqack_pat_off,		/* t_pat_off_proc		*/
  NULL,				/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  NULL,				/* t_pat_get_field_proc		*/
  NULL,				/* t_pat_set_field_proc		*/
  NULL,				/* t_pat_get_fields_proc	*/
  NULL,				/* t_pat_get_tmpl_proc		*/
  NULL,				/* t_pat_get_tmpl2_proc		*/
  NULL,				/* t_pat_has_opt_proc		*/
  NULL,				/* t_pat_adapt_len_proc		*/
  NULL,				/* t_pat_get_field_pat_proc	*/
  seqack_pat_extract,		/* t_pat_extract_proc		*/
  seqack_pat_insert,		/* t_pat_insert_proc		*/
  NULL,				/* t_pat_get_choices_proc	*/
};
