/*
** pat_icmp.c for  in 
** 
** Made by 
** Login   <vianney@epita.fr>
** 
** Started on  Wed Sep  1 06:43:27 1999 
** Last update Thu Oct 28 20:20:03 1999 
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "pat_icmp.h"
#include "pat_ip.h"
#include "pat_data.h"
#include "pat_8.h"
#include "pat_16.h"
#include "pat_32.h"
#include "pat_inaddr.h"
#include "pat_icmpcode.h"
#include "pat_time.h"

/*
Type    Name                                    Reference
----    -------------------------               ---------
  0     Echo Reply                               [RFC792]
  1     Unassigned                                  [JBP]
  2     Unassigned                                  [JBP]
  3     Destination Unreachable                  [RFC792]
  4     Source Quench                            [RFC792]
  5     Redirect                                 [RFC792]
  6     Alternate Host Address                      [JBP]
  7     Unassigned                                  [JBP]
  8     Echo                                     [RFC792]
  9     Router Advertisement                    [RFC1256]
 10     Router Selection                        [RFC1256]
 11     Time Exceeded                            [RFC792]
 12     Parameter Problem                        [RFC792]
 13     Timestamp                                [RFC792]
 14     Timestamp Reply                          [RFC792]
 15     Information Request                      [RFC792]
 16     Information Reply                        [RFC792]
 17     Address Mask Request                     [RFC950]
 18     Address Mask Reply                       [RFC950]
 19     Reserved (for Security)                    [Solo]
 20-29  Reserved (for Robustness Experiment)        [ZSu]
 30     Traceroute                              [RFC1393]
 31     Datagram Conversion Error               [RFC1475]
 32     Mobile Host Redirect              [David Johnson]
 33     IPv6 Where-Are-You                 [Bill Simpson]
 34     IPv6 I-Am-Here                     [Bill Simpson]
 35     Mobile Registration Request        [Bill Simpson]
 36     Mobile Registration Reply          [Bill Simpson]
 37-255 Reserved                                    [JBP]
 */

t_assoc				icmptype_assocs[] =
{
  {"echo_reply",		(VOID_PTR)ICMP_ECHO_REPLY},
  {"unreachable",		(VOID_PTR)ICMP_UNREACHABLE},
  {"source_quench",		(VOID_PTR)ICMP_SOURCE_QUENCH},
  {"redirect",			(VOID_PTR)ICMP_REDIRECT},
  {"alternate_host_address",	(VOID_PTR)6},
  {"echo_request",		(VOID_PTR)ICMP_ECHO_REQUEST},
  {"router_advertisement",	(VOID_PTR)ICMP_ROUTER_ADVERTISEMENT},
  {"router_selection",		(VOID_PTR)10},
  {"time_exceed",		(VOID_PTR)ICMP_TIME_EXCEED},
  {"parameter_problem",		(VOID_PTR)12},
  {"timestamp_request",		(VOID_PTR)ICMP_TS_REQUEST},
  {"timestamp_reply",		(VOID_PTR)ICMP_TS_REPLY},
  {"info_request",		(VOID_PTR)15},
  {"info_reply",		(VOID_PTR)16},
  {"mask_request",		(VOID_PTR)ICMP_MASK_REQUEST},
  {"mask_reply",		(VOID_PTR)ICMP_MASK_REPLY},
  {"traceroute",		(VOID_PTR)30},
  {"datagram_conversion_error",	(VOID_PTR)31},
  {"mobile_host_redirect",	(VOID_PTR)32},
  {"ipv6_where_are_you",	(VOID_PTR)33},
  {"ipv6_i_am_here",		(VOID_PTR)34},
  {"mobile_regist_request",	(VOID_PTR)35},
  {"mobile_regist_reply",	(VOID_PTR)36},
  {NULL,			NULL},
};

VOID_FUNC	icmp_compute_sum(ip,icmp)
t_ip		*ip;
t_icmp		*icmp;
{
  int		datalen;
  t_u16		zero;

  zero = 0;
  FBCOPY(&zero,&(icmp->cksum),sizeof (zero)); /* alignment */
  datalen = ip_get_len(ip) - ip_get_hl(ip) * 4;
  safe_htons(in_cksum((t_u16 *)icmp,datalen >> 1),&(icmp->cksum));
}

VOID_FUNC	icmp_set_proto(ip)
t_ip		*ip;
{
  ip_set_p(ip,IP_PROTO_ICMP);
}

VOID_FUNC	icmp_set_type(icmp,type)
t_icmp		*icmp;
int		type;
{
  icmp->type = type;
}

int		icmp_get_type(icmp)
t_icmp		*icmp;
{
  return (icmp->type);
}

VOID_FUNC	icmp_set_code(icmp,code)
t_icmp		*icmp;
int		code;
{
  icmp->code = code;
}

int		icmp_get_code(icmp)
t_icmp		*icmp;
{
  return (icmp->code);
}

VOID_FUNC	icmp_set_cksum(icmp,sum)
t_icmp		*icmp;
int		sum;
{
  safe_htons(sum,&(icmp->cksum));
}

int		icmp_get_cksum(icmp)
t_icmp		*icmp;
{
  return (safe_ntohs(&(icmp->cksum)));
}	

t_field				icmpmbz_fields[] = 
{
  {"mbz",	0,		&nu32_pat,			NULL},
  NULL_FIELD
};

char				*icmpmbz_itmpl = "\n\
<table _name=icmpmbz[%i%] width=100%%%% bgcolor=\"%%icmpmbzColor%%\">\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(icmpmbz[%i%].mbz)\">%%icmpmbz[%i%].mbz%%</a>\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

int	icmpmbz_chan;

PAT_NAME_GENERIC(icmpmbz_pat_name,
		 (VOID_PTR)&icmpmbz_chan,
		 "icmpmbz")

PAT_GET_FIELD_GENERIC(icmpmbz_pat_get_field,
		      icmpmbz_fields)

PAT_SET_FIELD_GENERIC(icmpmbz_pat_set_field,
		      icmpmbz_fields)

PAT_GET_FIELDS_GENERIC(icmpmbz_pat_get_fields,
		       icmpmbz_fields)

PAT_GET_FIELD_PAT_GENERIC(icmpmbz_pat_get_field_pat,
			  icmpmbz_fields)

PAT_GET_TMPL_GENERIC(icmpmbz_pat_get_tmpl,
		     (VOID_PTR)&icmpmbz_chan,
		     icmpmbz_itmpl)

PAT_OFF_GENERIC(icmpmbz_pat_off,
		4)

PAT_SUB_GENERIC(icmpmbz_pat_sub,
		&ip_pat)

t_pat				icmpmbz_pat = 
{
  icmpmbz_pat_name,		/* t_pat_name_proc		*/
  icmpmbz_pat_off,		/* t_pat_off_proc		*/
  icmpmbz_pat_sub,		/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  icmpmbz_pat_get_field,	/* t_pat_get_field_proc		*/
  icmpmbz_pat_set_field,	/* t_pat_set_field_proc		*/
  icmpmbz_pat_get_fields,	/* t_pat_get_fields_proc	*/
  icmpmbz_pat_get_tmpl,		/* t_pat_get_tmpl_proc		*/
  NULL,				/* t_pat_get_tmpl2_proc		*/
  NULL,				/* t_pat_has_opt_proc		*/
  NULL,				/* t_pat_adapt_len_proc		*/
  icmpmbz_pat_get_field_pat,	/* t_pat_get_field_pat_proc	*/
  NULL,				/* t_pat_extract_proc		*/
  NULL,				/* t_pat_insert_proc		*/
  NULL,				/* t_pat_get_choices_proc	*/
};


t_field				icmpredirect_fields[] = 
{
  {"router",	0,		&inaddr_pat,			NULL},
  {"Router",	0,		&inaddr_resolved_pat,		NULL},
  NULL_FIELD
};

char				*icmpredirect_itmpl = "\n\
<table _name=icmpredirect[%i%] width=100%%%% bgcolor=\"%%icmpredirectColor%%\">\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(icmpredirect[%i%].router)\">%%icmpredirect[%i%].router%%</a>\n\
(<a href=\"set(icmpredirect[%i%].Router)\">%%icmpredirect[%i%].Router%%</a>)\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

int	icmpredirect_chan;

PAT_NAME_GENERIC(icmpredirect_pat_name,
		 (VOID_PTR)&icmpredirect_chan,
		 "icmpredirect")

PAT_GET_FIELD_GENERIC(icmpredirect_pat_get_field,
		      icmpredirect_fields)

PAT_SET_FIELD_GENERIC(icmpredirect_pat_set_field,
		      icmpredirect_fields)

PAT_GET_FIELDS_GENERIC(icmpredirect_pat_get_fields,
		       icmpredirect_fields)

PAT_GET_FIELD_PAT_GENERIC(icmpredirect_pat_get_field_pat,
			  icmpredirect_fields)

PAT_GET_TMPL_GENERIC(icmpredirect_pat_get_tmpl,
		     (VOID_PTR)&icmpredirect_chan,
		     icmpredirect_itmpl)

PAT_OFF_GENERIC(icmpredirect_pat_off,
		4)    

PAT_SUB_GENERIC(icmpredirect_pat_sub,
		&ip_pat)

t_pat				icmpredirect_pat = 
{
  icmpredirect_pat_name,	/* t_pat_name_proc		*/
  icmpredirect_pat_off,		/* t_pat_off_proc		*/
  icmpredirect_pat_sub,		/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  icmpredirect_pat_get_field,	/* t_pat_get_field_proc		*/
  icmpredirect_pat_set_field,	/* t_pat_set_field_proc		*/
  icmpredirect_pat_get_fields,	/* t_pat_get_fields_proc	*/
  icmpredirect_pat_get_tmpl,	/* t_pat_get_tmpl_proc		*/
  NULL,				/* t_pat_get_tmpl2_proc		*/
  NULL,				/* t_pat_has_opt_proc		*/
  NULL,				/* t_pat_adapt_len_proc		*/
  icmpredirect_pat_get_field_pat,/* t_pat_get_field_pat_proc	*/
  NULL,				/* t_pat_extract_proc		*/
  NULL,				/* t_pat_insert_proc		*/
  NULL,				/* t_pat_get_choices_proc	*/
};

t_field				icmpmask_fields[] = 
{
  {"id",	0,		&nu16_pat,			NULL},
  {"seq",	2,		&nu16_pat,			NULL},
  {"mask",	4,		&inaddr_pat,			NULL},
  {"Mask",	4,		&inaddr_resolved_pat,		NULL},
  NULL_FIELD
};

char				*icmpmask_itmpl = "\n\
<table _name=icmpmask[%i%] width=100%%%% bgcolor=\"%%icmpmaskColor%%\">\n\
<tr>\n\
<td align=center width=50%%%%>\n\
<a href=\"set(icmpmask[%i%].id)\">%%icmpmask[%i%].id%%</a>\n\
</td>\n\
<td align=center width=50%%%%>\n\
<a href=\"set(icmpmask[%i%].seq)\">%%icmpmask[%i%].seq%%</a>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(icmpmask[%i%].Mask)\">%%icmpmask[%i%].Mask%%</a>\n\
(<a href=\"set(icmpmask[%i%].mask)\">%%icmpmask[%i%].mask%%</a>)\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

int	icmpmask_chan;

PAT_NAME_GENERIC(icmpmask_pat_name,
		 (VOID_PTR)&icmpmask_chan,
		 "icmpmask")

PAT_GET_FIELD_GENERIC(icmpmask_pat_get_field,
		      icmpmask_fields)

PAT_SET_FIELD_GENERIC(icmpmask_pat_set_field,
		      icmpmask_fields)

PAT_GET_FIELDS_GENERIC(icmpmask_pat_get_fields,
		       icmpmask_fields)

PAT_GET_FIELD_PAT_GENERIC(icmpmask_pat_get_field_pat,
			  icmpmask_fields)

PAT_GET_TMPL_GENERIC(icmpmask_pat_get_tmpl,
		     (VOID_PTR)&icmpmask_chan,
		     icmpmask_itmpl)

PAT_OFF_GENERIC(icmpmask_pat_off,
		8)

PAT_SUB_GENERIC(icmpmask_pat_sub,
		&data_pat)

t_pat				icmpmask_pat = 
{
  icmpmask_pat_name,		/* t_pat_name_proc		*/
  icmpmask_pat_off,		/* t_pat_off_proc		*/
  icmpmask_pat_sub,		/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  icmpmask_pat_get_field,	/* t_pat_get_field_proc		*/
  icmpmask_pat_set_field,	/* t_pat_set_field_proc		*/
  icmpmask_pat_get_fields,	/* t_pat_get_fields_proc	*/
  icmpmask_pat_get_tmpl,	/* t_pat_get_tmpl_proc		*/
  NULL,				/* t_pat_get_tmpl2_proc		*/
  NULL,				/* t_pat_has_opt_proc		*/
  NULL,				/* t_pat_adapt_len_proc		*/
  icmpmask_pat_get_field_pat,	/* t_pat_get_field_pat_proc	*/
  NULL,				/* t_pat_extract_proc		*/
  NULL,				/* t_pat_insert_proc		*/
  NULL,				/* t_pat_get_choices_proc	*/
};

t_field				icmpts_fields[] = 
{
  {"id",	0,		&nu16_pat,			NULL},
  {"seq",	2,		&nu16_pat,			NULL},
  {"Originatets",4,		&time_pat,			NULL},
  {"Receivets",	8,		&time_pat,			NULL},
  {"Transmitts",12,		&time_pat,			NULL},
  NULL_FIELD
};

char				*icmpts_itmpl = "\n\
<table _name=icmpts[%i%] width=100%%%% bgcolor=\"%%icmptsColor%%\">\n\
<tr>\n\
<td align=center width=50%%%%>\n\
<a href=\"set(icmpts[%i%].id)\">%%icmpts[%i%].id%%</a>\n\
</td>\n\
<td align=center width=50%%%%>\n\
<a href=\"set(icmpts[%i%].seq)\">%%icmpts[%i%].seq%%</a>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(icmpts[%i%].Originatets)\">%%icmpts[%i%].Originatets%%</a>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(icmpts[%i%].Receivets)\">%%icmpts[%i%].Receivets%%</a>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(icmpts[%i%].Transmitts)\">%%icmpts[%i%].Transmitts%%</a>\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

int	icmpts_chan;

PAT_NAME_GENERIC(icmpts_pat_name,
		 (VOID_PTR)&icmpts_chan,
		 "icmpts")

PAT_GET_FIELD_GENERIC(icmpts_pat_get_field,
		      icmpts_fields)

PAT_SET_FIELD_GENERIC(icmpts_pat_set_field,
		      icmpts_fields)

PAT_GET_FIELDS_GENERIC(icmpts_pat_get_fields,
		       icmpts_fields)

PAT_GET_FIELD_PAT_GENERIC(icmpts_pat_get_field_pat,
			  icmpts_fields)

PAT_GET_TMPL_GENERIC(icmpts_pat_get_tmpl,
		     (VOID_PTR)&icmpts_chan,
		     icmpts_itmpl)

PAT_OFF_GENERIC(icmpts_pat_off,
		16)

PAT_SUB_GENERIC(icmpts_pat_sub,
		&data_pat)
	
t_pat				icmpts_pat = 
{
  icmpts_pat_name,		/* t_pat_name_proc		*/
  icmpts_pat_off,		/* t_pat_off_proc		*/
  icmpts_pat_sub,		/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  icmpts_pat_get_field,		/* t_pat_get_field_proc		*/
  icmpts_pat_set_field,		/* t_pat_set_field_proc		*/
  icmpts_pat_get_fields,	/* t_pat_get_fields_proc	*/
  icmpts_pat_get_tmpl,		/* t_pat_get_tmpl_proc		*/
  NULL,				/* t_pat_get_tmpl2_proc		*/
  NULL,				/* t_pat_has_opt_proc		*/
  NULL,				/* t_pat_adapt_len_proc		*/
  icmpts_pat_get_field_pat,	/* t_pat_get_field_pat_proc	*/
  NULL,				/* t_pat_extract_proc		*/
  NULL,				/* t_pat_insert_proc		*/
  NULL,				/* t_pat_get_choices_proc	*/
};

t_field				icmp_fields[] = 
{
  {"type",	OFFSET(t_icmp *,type),	&u8_pat,			NULL},
  {"Type",	OFFSET(t_icmp *,type),	&u8assoc_pat,	     icmptype_assocs},
  {"code",	OFFSET(t_icmp *,code),	&u8_pat,			NULL},
  {"Code",	OFFSET(t_icmp *,type),	&icmpcodeagainsttype_pat,	NULL},
  {"cksum",	OFFSET(t_icmp *,cksum),	&nu16_pat,			NULL},
  NULL_FIELD
};

char				*icmp_itmpl = "\n\
<table _name=icmp[%i%] width=100%%%% bgcolor=\"%%icmpColor%%\">\n\
<tr>\n\
<td align=center width=25%%%%>\n\
<a href=\"set(icmp[%i%].Type)\">%%icmp[%i%].Type%%</a>\n\
(<a href=\"set(icmp[%i%].type)\">%%icmp[%i%].type%%</a>)\n\
</td>\n\
<td align=center width=25%%%%>\n\
<_tiny><a href=\"set(icmp[%i%].Code)\">%%icmp[%i%].Code%%</a></_tiny>\n\
(<a href=\"set(icmp[%i%].code)\">%%icmp[%i%].code%%</a>)\n\
</td>\n\
<td align=center width=50%%%%>\n\
<a href=\"set(icmp[%i%].cksum)\">%%icmp[%i%].cksum%%</a>\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

int	icmp_chan;

PAT_NAME_GENERIC(icmp_pat_name,
		 (VOID_PTR)&icmp_chan,
		 "icmp")

PAT_GET_FIELD_GENERIC(icmp_pat_get_field,
		      icmp_fields)

PAT_SET_FIELD_GENERIC(icmp_pat_set_field,
		      icmp_fields)

PAT_GET_FIELDS_GENERIC(icmp_pat_get_fields,
		       icmp_fields)

PAT_GET_FIELD_PAT_GENERIC(icmp_pat_get_field_pat,
			  icmp_fields)

PAT_GET_TMPL_GENERIC(icmp_pat_get_tmpl,
		     (VOID_PTR)&icmp_chan,
		     icmp_itmpl)

PAT_OFF_GENERIC(icmp_pat_off,
		ICMP_HLEN)

PAT_SUM_DECL(icmp_pat_sum)
{
  t_icmp	*icmp;
  t_ip		*ip;
  
  PAT_ICMP_CHECK(icmp,buf,len);
  PAT_IP_CHECK(ip,up_buf,up_len);
  if (ip_get_len(ip) != up_len)
    return (ERR_PAT_BAD_LEN);
  if (ip_get_hl(ip) * 4 < IP_MINHLEN)
    return (ERR_PAT_BAD_HEADER);
  icmp_compute_sum(ip,icmp);
  return (0);
}

PAT_SUB_DECL(icmp_pat_sub)
{
  t_icmp	*icmp;	
  
  PAT_ICMP_CHECK(icmp,buf,len);
  switch (icmp_get_type(icmp))
    {
    case ICMP_REDIRECT:
      (*pat_return) = &icmpredirect_pat;
      return (0);
    case ICMP_SOURCE_QUENCH:
    case ICMP_UNREACHABLE:
    case ICMP_TIME_EXCEED:
      (*pat_return) = &icmpmbz_pat;
      return (0);
    case ICMP_TS_REQUEST:
    case ICMP_TS_REPLY:
      (*pat_return) = &icmpts_pat;
      return (0);
    case ICMP_MASK_REQUEST:
    case ICMP_MASK_REPLY:
      (*pat_return) = &icmpmask_pat;
      return (0);
    }
  (*pat_return) = &data_pat;
  return (0);
}

t_pat				icmp_pat = 
{
  icmp_pat_name,		/* t_pat_name_proc		*/
  icmp_pat_off,			/* t_pat_off_proc		*/
  icmp_pat_sub,			/* t_pat_sub_proc		*/
  icmp_pat_sum,			/* t_pat_sum_proc		*/
  icmp_pat_get_field,		/* t_pat_get_field_proc		*/
  icmp_pat_set_field,		/* t_pat_set_field_proc		*/
  icmp_pat_get_fields,		/* t_pat_get_fields_proc	*/
  icmp_pat_get_tmpl,		/* t_pat_get_tmpl_proc		*/
  NULL,				/* t_pat_get_tmpl2_proc		*/
  NULL,				/* t_pat_has_opt_proc		*/
  NULL,				/* t_pat_adapt_len_proc		*/
  icmp_pat_get_field_pat,	/* t_pat_get_field_pat_proc	*/
  NULL,				/* t_pat_extract_proc		*/
  NULL,				/* t_pat_insert_proc		*/
  NULL,				/* t_pat_get_choices_proc	*/
};
