/*
** pat_bootp.c for  in 
** 
** Made by 
** Login   <vianney@epita.fr>
** 
** Started on  Wed Sep  1 06:44:18 1999 
** Last update Thu Oct 28 20:20:13 1999 
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "pat_bootp.h"
#include "pat_ip.h"
#include "pat_ether.h"
#include "pat_data.h"
#include "pat_32.h"
#include "pat_16.h"
#include "pat_8.h"
#include "pat_inaddr.h"
#include "pat_buf.h"
#include "pat_sz.h"
#include "pat_time.h"

t_boolean			pat_bootp_do_vendor = TRUE;
t_boolean			pat_bootp_vendor_gt_64 = TRUE;

char				rfc1048_magic[] = {99,130,83,99};

char				*rfc2132optdata_itmpl = "\n\
<table _name=rfc2132optdata[%i%] width=100%%%% bgcolor=\"%%rfc2132optColor%%\">\n\
<tr>\n\
<td width=100%%%%>\n\
<code>\n\
%%rfc2132optdata[%i%].cookedhtmlbuf%%\n\
</code>\n\
</tr>\n\
</table>\n\
<br>\n\
";

int	rfc2132optdata_chan;

PAT_NAME_GENERIC(rfc2132optdata_pat_name,
		 (VOID_PTR)&rfc2132optdata_chan,
		 "rfc2132optdata")

PAT_GET_TMPL_GENERIC(rfc2132optdata_pat_get_tmpl,
		     (VOID_PTR)&rfc2132optdata_chan,
		     rfc2132optdata_itmpl)

t_pat				rfc2132optdata_pat = 
{
  rfc2132optdata_pat_name,	/* t_pat_name_proc		*/
  data_pat_off,			/* t_pat_off_proc		*/
  NULL,				/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  data_pat_get_field,		/* t_pat_get_field_proc		*/
  NULL,				/* t_pat_set_field_proc		*/
  data_pat_get_fields,		/* t_pat_get_fields_proc	*/
  rfc2132optdata_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		*/
  NULL,				/* t_pat_get_field_pat_proc	*/
  NULL,				/* t_pat_extract_proc		*/
  NULL,				/* t_pat_insert_proc		*/
  NULL,				/* t_pat_get_choices_proc	*/
};

t_assoc				rfc2132opt_assocs[] =
{
  {"pad",			(VOID_PTR)0},
  {"subnet_mask",		(VOID_PTR)1},
  {"time_offset",		(VOID_PTR)2},
  {"router",			(VOID_PTR)3},
  {"time_server",		(VOID_PTR)4},
  {"name_server",		(VOID_PTR)5},
  {"domain_name_server",	(VOID_PTR)6},
  {"log_server",		(VOID_PTR)7},
  {"cookie_server",		(VOID_PTR)8},
  {"lpr_server",		(VOID_PTR)9},
  {"impress_server",		(VOID_PTR)10},
  {"resource_location",		(VOID_PTR)11},
  {"host_name",			(VOID_PTR)12},
  {"boot_file_size",		(VOID_PTR)13},
  {"merit_dump",		(VOID_PTR)14},
  {"domain_name",		(VOID_PTR)15},
  {"swap_server",		(VOID_PTR)16},
  {"root_path",			(VOID_PTR)17},
  {"extensions_path",		(VOID_PTR)18},
  {"ip_forwarding",		(VOID_PTR)19},
  {"non_local_source_routing",	(VOID_PTR)20},
  {"policy_filter",		(VOID_PTR)21},
  {"max_dgram_reass_size",	(VOID_PTR)22},
  {"default_ip_ttl",		(VOID_PTR)23},
  {"path_mtu_aging_timeout",	(VOID_PTR)24},
  {"path_mtu_plateau_table",	(VOID_PTR)25},
  {"interface_mtu",		(VOID_PTR)26},
  {"all_subnets_are_local",	(VOID_PTR)27},
  {"broadcast_address",		(VOID_PTR)28},
  {"perform_mask_discovery",	(VOID_PTR)29},
  {"mask_supplier",		(VOID_PTR)30},
  {"perform_router_discovery",	(VOID_PTR)31},
  {"router_solicitation_address",(VOID_PTR)32},
  {"static_route",		(VOID_PTR)33},
  {"trailer_encapsulation",	(VOID_PTR)34},
  {"arp_cache_timeout",		(VOID_PTR)35},
  {"ethernet_encaps",		(VOID_PTR)36},
  {"tcp_default_ttl",		(VOID_PTR)37},
  {"tcp_keepalive_interval",	(VOID_PTR)38},
  {"tcp_keepalive_garbage",	(VOID_PTR)39},
  {"nis_domain",		(VOID_PTR)40},
  {"nis_servers",		(VOID_PTR)41},
  {"ntp_servers",		(VOID_PTR)42},
  {"vendor_specific",		(VOID_PTR)43},
  {"netbios_name_servers",	(VOID_PTR)44},
  {"netbios_dgram_dist_servers",(VOID_PTR)45},
  {"netbios_node_type",		(VOID_PTR)46},
  {"netbios_scope",		(VOID_PTR)47},
  {"x_font_servers",		(VOID_PTR)48},
  {"xdm_servers",		(VOID_PTR)49},
  {"requested_ip_address",	(VOID_PTR)50},
  {"ip_address_lease_time",	(VOID_PTR)51},
  {"overload",			(VOID_PTR)52},
  {"dhcp_message_type",		(VOID_PTR)53},
  {"server_identifier",		(VOID_PTR)54},
  {"parameter_request_list",	(VOID_PTR)55},
  {"message",			(VOID_PTR)56},
  {"max_dhcp_message_size",	(VOID_PTR)57},
  {"renewal_time_value",	(VOID_PTR)58},
  {"rebinding_time_value",	(VOID_PTR)59},
  {"vendor_class_identifier",	(VOID_PTR)60},
  {"client_identifier",		(VOID_PTR)61},
  {"nis+_domain",		(VOID_PTR)64},
  {"nis+_servers",		(VOID_PTR)65},
  {"tftp_server_name",		(VOID_PTR)66},
  {"bootfile_name",		(VOID_PTR)67},
  {"mobile_ip_home_agent",	(VOID_PTR)68},
  {"smtp_servers",		(VOID_PTR)69},
  {"pop3_servers",		(VOID_PTR)70},
  {"nntp_servers",		(VOID_PTR)71},
  {"www_servers",		(VOID_PTR)72},
  {"finger_servers",		(VOID_PTR)73},
  {"irc_servers",		(VOID_PTR)74},
  {"streettalk_servers",	(VOID_PTR)75},
  {"stda_servers",		(VOID_PTR)76},
  {"end",			(VOID_PTR)255},
  NULL_ASSOC
};

t_assoc				dhcptype_assocs[] = 
{
  {"dhcpdiscover",		(VOID_PTR)1},
  {"dhcpoffer",			(VOID_PTR)2},
  {"dhcprequest",		(VOID_PTR)3},
  {"dhcpdecline",		(VOID_PTR)4},
  {"dhcpack",			(VOID_PTR)5},
  {"dhcpnack",			(VOID_PTR)6},
  {"dhcprelease",		(VOID_PTR)7},
  {"dhcpinform",		(VOID_PTR)8},
  NULL_ASSOC
};

t_field				dhcptype_fields[] = 
{
  {"type",	0,		&u8_pat,	NULL},
  {"Type",	0,		&u8assoc_pat,	dhcptype_assocs},
  NULL_FIELD
};

char				*dhcptype_itmpl = "\n\
<table _name=dhcptype[%i%] width=100%%%% bgcolor=\"%%dhcptypeColor%%\">\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<small>\n\
<a href=\"set(dhcptype[%i%].Type)\">%%dhcptype[%i%].Type%%</a>\n\
(<a href=\"set(dhcptype[%i%].type)\">%%dhcptype[%i%].type%%</a>)\n\
</small>\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

int	dhcptype_chan;

PAT_NAME_GENERIC(dhcptype_pat_name,
		 (VOID_PTR)&dhcptype_chan,
		 "dhcptype")

PAT_GET_FIELD_GENERIC(dhcptype_pat_get_field,
		      dhcptype_fields)

PAT_SET_FIELD_GENERIC(dhcptype_pat_set_field,
		      dhcptype_fields)

PAT_GET_FIELDS_GENERIC(dhcptype_pat_get_fields,
		       dhcptype_fields)

PAT_GET_FIELD_PAT_GENERIC(dhcptype_pat_get_field_pat,
			  dhcptype_fields)

PAT_GET_TMPL_GENERIC(dhcptype_pat_get_tmpl,
		     (VOID_PTR)&dhcptype_pat,
		     dhcptype_itmpl)

PAT_OFF_GENERIC(dhcptype_pat_off,
		1)

PAT_SUB_GENERIC(dhcptype_pat_sub,
		&dhcptype_pat)

t_pat				dhcptype_pat = 
{
  dhcptype_pat_name,		/* t_pat_name_proc		*/
  dhcptype_pat_off,		/* t_pat_off_proc		*/
  dhcptype_pat_sub,		/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  dhcptype_pat_get_field,	/* t_pat_get_field_proc		*/
  dhcptype_pat_set_field,	/* t_pat_set_field_proc		*/
  dhcptype_pat_get_fields,	/* t_pat_get_fields_proc	*/
  dhcptype_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		*/
  dhcptype_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_mask_def			netbiostype_mask_defs[] = 
{
  {"b",				0x1},
  {"p",				0x2},
  {"m",				0x4},
  {"h",				0x8},
  NULL_MASK_DEF
};

t_field				netbiostype_fields[] = 
{
  {"type",	0,		&u8_pat,	NULL},
  {"Type",	0,		&u8mask_pat,	netbiostype_mask_defs},
  NULL_FIELD
};

char				*netbiostype_itmpl = "\n\
<table _name=netbiostype[%i%] width=100%%%% bgcolor=\"%%netbiostypeColor%%\">\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<small>\n\
<a href=\"set(netbiostype[%i%].Type)\">%%netbiostype[%i%].Type%%</a>\n\
(<a href=\"set(netbiostype[%i%].type)\">%%netbiostype[%i%].type%%</a>)\n\
</small>\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

int	netbiostype_chan;

PAT_NAME_GENERIC(netbiostype_pat_name,
		 (VOID_PTR)&netbiostype_chan,
		 "netbiostype")

PAT_GET_FIELD_GENERIC(netbiostype_pat_get_field,
		      netbiostype_fields)

PAT_SET_FIELD_GENERIC(netbiostype_pat_set_field,
		      netbiostype_fields)

PAT_GET_FIELDS_GENERIC(netbiostype_pat_get_fields,
		       netbiostype_fields)

PAT_GET_FIELD_PAT_GENERIC(netbiostype_pat_get_field_pat,
			  netbiostype_fields)

PAT_GET_TMPL_GENERIC(netbiostype_pat_get_tmpl,
		     (VOID_PTR)&netbiostype_pat,
		     netbiostype_itmpl)

PAT_OFF_GENERIC(netbiostype_pat_off,
		1)

PAT_SUB_GENERIC(netbiostype_pat_sub,
		&netbiostype_pat)

t_pat				netbiostype_pat = 
{
  netbiostype_pat_name,		/* t_pat_name_proc		*/
  netbiostype_pat_off,		/* t_pat_off_proc		*/
  netbiostype_pat_sub,		/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  netbiostype_pat_get_field,	/* t_pat_get_field_proc		*/
  netbiostype_pat_set_field,	/* t_pat_set_field_proc		*/
  netbiostype_pat_get_fields,	/* t_pat_get_fields_proc	*/
  netbiostype_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		*/
  netbiostype_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_assoc				dhcpoverload_assocs[] = 
{
  {"file",			(VOID_PTR)1},
  {"sname",			(VOID_PTR)2},
  {"both",			(VOID_PTR)3},
  NULL_ASSOC
};

t_field				dhcpoverload_fields[] = 
{
  {"overload",	0,		&u8_pat,	NULL},
  {"Overload",	0,		&u8assoc_pat,	dhcpoverload_assocs},
  NULL_FIELD
};

char				*dhcpoverload_itmpl = "\n\
<table _name=dhcpoverload[%i%] width=100%%%% bgcolor=\"%%dhcpoverloadColor%%\">\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<small>\n\
<a href=\"set(dhcpoverload[%i%].Overload)\">%%dhcpoverload[%i%].Overload%%</a>\n\
(<a href=\"set(dhcpoverload[%i%].overload)\">%%dhcpoverload[%i%].overload%%</a>)\n\
</small>\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

int	dhcpoverload_chan;

PAT_NAME_GENERIC(dhcpoverload_pat_name,
		 (VOID_PTR)&dhcpoverload_chan,
		 "dhcpoverload")

PAT_GET_FIELD_GENERIC(dhcpoverload_pat_get_field,
		      dhcpoverload_fields)

PAT_SET_FIELD_GENERIC(dhcpoverload_pat_set_field,
		      dhcpoverload_fields)

PAT_GET_FIELDS_GENERIC(dhcpoverload_pat_get_fields,
		       dhcpoverload_fields)

PAT_GET_FIELD_PAT_GENERIC(dhcpoverload_pat_get_field_pat,
			  dhcpoverload_fields)

PAT_GET_TMPL_GENERIC(dhcpoverload_pat_get_tmpl,
		     (VOID_PTR)&dhcpoverload_pat,
		     dhcpoverload_itmpl)

PAT_OFF_GENERIC(dhcpoverload_pat_off,
		1)

PAT_SUB_GENERIC(dhcpoverload_pat_sub,
		&dhcpoverload_pat)

t_pat				dhcpoverload_pat = 
{
  dhcpoverload_pat_name,	/* t_pat_name_proc		*/
  dhcpoverload_pat_off,		/* t_pat_off_proc		*/
  dhcpoverload_pat_sub,		/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  dhcpoverload_pat_get_field,	/* t_pat_get_field_proc		*/
  dhcpoverload_pat_set_field,	/* t_pat_set_field_proc		*/
  dhcpoverload_pat_get_fields,	/* t_pat_get_fields_proc	*/
  dhcpoverload_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		*/
  dhcpoverload_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				dhcpparam_fields[] = 
{
  {"tag",	0,		&u8_pat,	NULL},
  {"Tag",	0,		&u8assoc_pat,	rfc2132opt_assocs},
  NULL_FIELD
};

char				*dhcpparam_itmpl = "\n\
<table _name=dhcpparam[%i%] width=100%%%% bgcolor=\"%%dhcpparamColor%%\">\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<small>\n\
<a href=\"set(dhcpparam[%i%].Tag)\">%%dhcpparam[%i%].Tag%%</a>\n\
(<a href=\"set(dhcpparam[%i%].tag)\">%%dhcpparam[%i%].tag%%</a>)\n\
</small>\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

int	dhcpparam_chan;

PAT_NAME_GENERIC(dhcpparam_pat_name,
		 (VOID_PTR)&dhcpparam_chan,
		 "dhcpparam")

PAT_GET_FIELD_GENERIC(dhcpparam_pat_get_field,
		      dhcpparam_fields)

PAT_SET_FIELD_GENERIC(dhcpparam_pat_set_field,
		      dhcpparam_fields)

PAT_GET_FIELDS_GENERIC(dhcpparam_pat_get_fields,
		       dhcpparam_fields)

PAT_GET_FIELD_PAT_GENERIC(dhcpparam_pat_get_field_pat,
			  dhcpparam_fields)

PAT_GET_TMPL_GENERIC(dhcpparam_pat_get_tmpl,
		     (VOID_PTR)&dhcpparam_pat,
		     dhcpparam_itmpl)

PAT_OFF_GENERIC(dhcpparam_pat_off,
		1)

PAT_SUB_GENERIC(dhcpparam_pat_sub,
		&dhcpparam_pat)

t_pat				dhcpparam_pat = 
{
  dhcpparam_pat_name,		/* t_pat_name_proc		*/
  dhcpparam_pat_off,		/* t_pat_off_proc		*/
  dhcpparam_pat_sub,		/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  dhcpparam_pat_get_field,	/* t_pat_get_field_proc		*/
  dhcpparam_pat_set_field,	/* t_pat_set_field_proc		*/
  dhcpparam_pat_get_fields,	/* t_pat_get_fields_proc	*/
  dhcpparam_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		*/
  dhcpparam_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_assoc				rfc2132opt_sub_assocs[] = 
{
  {(VOID_PTR)1,			(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)2,			(VOID_PTR)&time_pat},
  {(VOID_PTR)3,			(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)4,			(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)5,			(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)6,			(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)7,			(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)8,			(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)9,			(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)10,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)11,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)12,		(VOID_PTR)&bufstruntil_pat},
  {(VOID_PTR)13,		(VOID_PTR)&nu16_pat},
  {(VOID_PTR)14,		(VOID_PTR)&bufstruntil_pat},
  {(VOID_PTR)15,		(VOID_PTR)&bufstruntil_pat},
  {(VOID_PTR)16,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)17,		(VOID_PTR)&bufstruntil_pat},
  {(VOID_PTR)18,		(VOID_PTR)&bufstruntil_pat},
  {(VOID_PTR)19,		(VOID_PTR)&u8_pat},
  {(VOID_PTR)20,		(VOID_PTR)&u8_pat},
  {(VOID_PTR)21,		(VOID_PTR)&inaddrmask_pat},
  {(VOID_PTR)22,		(VOID_PTR)&nu16_pat},
  {(VOID_PTR)23,		(VOID_PTR)&u8_pat},
  {(VOID_PTR)24,		(VOID_PTR)&nu32_pat},
  {(VOID_PTR)25,		(VOID_PTR)&nu16_pat},
  {(VOID_PTR)26,		(VOID_PTR)&nu16_pat},
  {(VOID_PTR)27,		(VOID_PTR)&u8_pat},
  {(VOID_PTR)28,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)29,		(VOID_PTR)&u8_pat},
  {(VOID_PTR)30,		(VOID_PTR)&u8_pat},
  {(VOID_PTR)31,		(VOID_PTR)&u8_pat},
  {(VOID_PTR)32,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)33,		(VOID_PTR)&inaddrrouter_pat},
  {(VOID_PTR)34,		(VOID_PTR)&u8_pat},
  {(VOID_PTR)35,		(VOID_PTR)&nu32_pat},
  {(VOID_PTR)36,		(VOID_PTR)&u8_pat},
  {(VOID_PTR)37,		(VOID_PTR)&u8_pat},
  {(VOID_PTR)38,		(VOID_PTR)&nu32_pat},
  {(VOID_PTR)39,		(VOID_PTR)&u8_pat},
  {(VOID_PTR)40,		(VOID_PTR)&bufstruntil_pat},
  {(VOID_PTR)41,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)42,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)43,		(VOID_PTR)&data_pat},
  {(VOID_PTR)44,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)45,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)46,		(VOID_PTR)&netbiostype_pat},
  {(VOID_PTR)48,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)49,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)50,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)51,		(VOID_PTR)&nu32_pat},
  {(VOID_PTR)52,		(VOID_PTR)&dhcpoverload_pat},
  {(VOID_PTR)53,		(VOID_PTR)&dhcptype_pat},
  {(VOID_PTR)54,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)55,		(VOID_PTR)&dhcpparam_pat},
  
  {(VOID_PTR)57,		(VOID_PTR)&nu16_pat},
  {(VOID_PTR)58,		(VOID_PTR)&nu32_pat},
  {(VOID_PTR)59,		(VOID_PTR)&nu32_pat},
  {(VOID_PTR)60,		(VOID_PTR)&bufstruntil_pat},

  {(VOID_PTR)64,		(VOID_PTR)&bufstruntil_pat},
  {(VOID_PTR)65,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)66,		(VOID_PTR)&bufstruntil_pat},
  {(VOID_PTR)67,		(VOID_PTR)&bufstruntil_pat},
  {(VOID_PTR)68,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)69,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)70,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)71,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)72,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)73,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)74,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)75,		(VOID_PTR)&inaddr_pat},
  {(VOID_PTR)76,		(VOID_PTR)&inaddr_pat},
  NOT_NULL_ASSOC
};

t_field				rfc2132opt_simple_fields[] = 
{
  {"tag",	0,	&u8_pat,		NULL},
  {"Tag",	0,	&u8assoc_pat,	(VOID_PTR)rfc2132opt_assocs},
  NULL_FIELD
};

t_field				rfc2132opt_double_fields[] = 
{
  {"tag",	0,	&u8_pat,		NULL},
  {"Tag",	0,	&u8assoc_pat,	(VOID_PTR)rfc2132opt_assocs},
  {"len",	1,	&u8_pat,		NULL},
  NULL_FIELD
};

t_field			*rfc2132opt_get_fields(buf,len,status)
char			*buf;
int			len;
t_status		*status;
{
  if (len < 1)
    {
      *status = ERR_PAT_TRUNC_PAT;
      return (NULL);
    }
  switch ((t_u8)(buf[0]))
    {
    case RFC2132OPT_PAD:
    case RFC2132OPT_END:
      return (rfc2132opt_simple_fields);
    default:
      return (rfc2132opt_double_fields);
    }
}

char				*rfc2132opt_simple_itmpl = "\n\
<table _name=rfc2132opt[%i%] bgcolor=\"%%rfc2132optColor%%\" width=100%%%%>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<small>\n\
<a href=\"set(rfc2132opt[%i%].Tag)\">%%rfc2132opt[%i%].Tag%%</a>\n\
(<a href=\"set(rfc2132opt[%i%].tag)\">%%rfc2132opt[%i%].tag%%</a>)\n\
</small>\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

char				*rfc2132opt_double_itmpl = "\n\
<table _name=rfc2132opt[%i%] bgcolor=\"%%rfc2132optColor%%\" width=100%%%%>\n\
<tr>\n\
<td align=center width=50%%%%>\n\
<small>\n\
<a href=\"set(rfc2132opt[%i%].Tag)\">%%rfc2132opt[%i%].Tag%%</a>\n\
(<a href=\"set(rfc2132opt[%i%].tag)\">%%rfc2132opt[%i%].tag%%</a>)\n\
</small>\n\
</td>\n\
<td align=center width=50%%%%>\n\
<small>\n\
<a href=\"set(rfc2132opt[%i%].len)\">%%rfc2132opt[%i%].len%%</a>\n\
</small>\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

char			*rfc2132opt_get_itmpl(buf,len,status)
char			*buf;
int			len;
t_status		*status;
{
  if (len < 1)
    {
      *status = ERR_PAT_TRUNC_PAT;
      return (NULL);
    }
  switch ((t_u8)(buf[0]))
    {
    case RFC2132OPT_PAD:
    case RFC2132OPT_END:
      return (rfc2132opt_simple_itmpl);
    default:
      return (rfc2132opt_double_itmpl);
    }
}

int		rfc2132opt_chan;

PAT_NAME_GENERIC(rfc2132opt_pat_name,
		 (VOID_PTR)&rfc2132opt_chan,
		 "rfc2132opt")

PAT_OFF_DECL(rfc2132opt_pat_off)
{
  if (len < 1)
    return (ERR_PAT_TRUNC_PAT);
  switch ((t_u8)(buf[0]))
    {
    case RFC2132OPT_PAD:
    case RFC2132OPT_END:
      (*off_return) = 1;
      return (0);
    }
  if (len < 2)
    return (ERR_PAT_TRUNC_PAT);
  (*off_return) = (t_off)(t_u8)(buf[1]) + 2;
  return (0);
}

PAT_SUB_DECL(rfc2132opt_pat_sub)
{
  if (len < 1)
    return (ERR_PAT_TRUNC_PAT);
  switch ((t_u8)(buf[0]))
    {
    case RFC2132OPT_END:
      (*pat_return) = &rfc2132optdata_pat;
      return (0);
    }
  (*pat_return) = &rfc2132opt_pat;
  return (0);
}

PAT_GET_FIELD_DECL(rfc2132opt_pat_get_field)
{
  t_field			*fields;
  t_field			*fieldptr;
  t_status			status;

  if ((fields = rfc2132opt_get_fields(buf,
				      len,
				      &status)) == NULL)
    return (status);
  fieldptr = NULL;
  while (fields->name)
    {
      if (!strcmp(fields->name,field))
	fieldptr = fields;
      fields++;
    }
  if (!fieldptr)
    return (ERR_PAT_NO_SUCH_FIELD);
  return (get_field_to_str(buf,
			   len,
			   fieldptr,
			   str,
			   max_len));
}

PAT_SET_FIELD_DECL(rfc2132opt_pat_set_field)
{
  t_field			*fields;
  t_field			*fieldptr;
  t_status			status;
  
  if ((fields = rfc2132opt_get_fields(buf,
				      len,
				      &status)) == NULL)
    return (status);
  fieldptr = NULL;
  while (fields->name)
    {
      if (!strcmp(fields->name,field))
	fieldptr = fields;
      fields++;
    }
  if (!fieldptr)
    return (ERR_PAT_NO_SUCH_FIELD);
  return (set_field_from_str(buf,
			     len,
			     fieldptr,
			     value));
}

PAT_GET_FIELD_PAT_DECL(rfc2132opt_pat_get_field_pat)
{
  t_field			*fields;	
  t_status			status;

  if ((fields = rfc2132opt_get_fields(buf,
				      len,
				      &status)) == NULL)
    return (status);
  while (fields->name)
    {
      if (!strcmp(field,fields->name))
	{
	  (*pat_return) = fields->pat;
	  (*data_return) = fields->data;
	  return (0);
	}
      fields++;
    }
  return (ERR_PAT_NO_SUCH_FIELD);
}

PAT_GET_TMPL_DECL(rfc2132opt_pat_get_tmpl)
{
  char		*itmpl;
  t_hash_elt	*he;
  int		i;
  t_status	status;  

  if ((itmpl = rfc2132opt_get_itmpl(buf,
				    len,
				    &status)) == NULL)
    return (status);
  if (he = id_get(id,
		  (VOID_PTR)&rfc2132opt_chan))
    i = (int)(he->value);
  else
    i = 0;
  if ((status = itmpl_format(i,
			     itmpl,
			     str,
			     max_len)) != 0)
    return (status);
  if ((status = id_override(id,
			    (VOID_PTR)&rfc2132opt_chan,
			    (VOID_PTR)(++i))) != 0)
    return (status);
  return (0);
}

PAT_HAS_OPT_DECL(rfc2132opt_pat_has_opt)
{
  t_assoc		*assoc;
  int			tag;
  int			i;

  if (len < 1)
    return (ERR_PAT_TRUNC_PAT);
  tag = (t_u8)(buf[0]);
  if (tag == RFC2132OPT_PAD || tag == RFC2132OPT_END)
    {
      (*has_opt_return) = FALSE;
      return (0);
    }
  if (len < 2)
    return (ERR_PAT_TRUNC_PAT);
  i = 0;
  assoc = rfc2132opt_sub_assocs;
  while (i < ARRAY_COUNT(rfc2132opt_sub_assocs))
    {
      if (tag == (int)(assoc->left))
	{
	  (*has_opt_return) = TRUE;
	  (*opt_off_return) = 2;
	  (*opt_len_return) = (t_u8)(buf[1]);
	  (*opt_pat_return) = (t_pat *)(assoc->right);
	  return (0);
	}
      i++;
      assoc++;
    }
  (*has_opt_return) = FALSE;
  return (0);
}
    
t_pat				rfc2132opt_pat = 
{
  rfc2132opt_pat_name,		/* t_pat_name_proc		*/
  rfc2132opt_pat_off,		/* t_pat_off_proc		*/
  rfc2132opt_pat_sub,		/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  rfc2132opt_pat_get_field,	/* t_pat_get_field_proc		*/
  rfc2132opt_pat_set_field,	/* t_pat_set_field_proc		*/
  NULL,				/* t_pat_get_fields_proc	*/
  rfc2132opt_pat_get_tmpl,	/* t_pat_get_tmpl_proc		*/
  NULL,				/* t_pat_get_tmpl2_proc		*/
  rfc2132opt_pat_has_opt,	/* t_pat_has_opt_proc		*/
  NULL,				/* t_pat_adapt_len_proc		*/
  rfc2132opt_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_assoc			bootp_op_assocs[] = 
{
  {"request",		(VOID_PTR)1},
  {"reply",		(VOID_PTR)2},
  NULL_ASSOC
};

t_assoc			bootp_htype_assocs[] =
{
  {"ether",		(VOID_PTR)1},
  NULL_ASSOC
};

t_assoc			bootp_magic_assocs[] = 
{
  {"rfc1048",		rfc1048_magic},
  NULL_ASSOC
};

t_buf_assocs_data	bootp_magic_bad = 
{
  4,
  bootp_magic_assocs
};

t_field				bootp_fields[] = 
{
  {"op",	OFFSET(t_bootp *,op),		&u8_pat,		NULL},
  {"Op",	OFFSET(t_bootp *,op),		&u8assoc_pat,bootp_op_assocs},
  {"htype",	OFFSET(t_bootp *,htype),	&u8_pat,		NULL},
  {"Htype",	OFFSET(t_bootp *,htype),      &u8assoc_pat,bootp_htype_assocs},
  {"hlen",	OFFSET(t_bootp *,hlen),	        &u8_pat,		NULL},
  {"hops",	OFFSET(t_bootp *,hops),		&u8_pat,		NULL},
  {"xid",	OFFSET(t_bootp *,xid),		&u32_pat,		NULL},
  {"secs",	OFFSET(t_bootp *,secs),		&u16_pat,		NULL},
  {"unused",	OFFSET(t_bootp *,unused),	&u16_pat,		NULL},
  {"caddr",	OFFSET(t_bootp *,caddr),	&inaddr_pat,		NULL},
  {"Caddr",	OFFSET(t_bootp *,caddr),	&inaddr_resolved_pat,	NULL},
  {"yaddr",	OFFSET(t_bootp *,yaddr),	&inaddr_pat,		NULL},
  {"Yaddr",	OFFSET(t_bootp *,yaddr),	&inaddr_resolved_pat,	NULL},
  {"saddr",	OFFSET(t_bootp *,saddr),	&inaddr_pat,		NULL},
  {"Saddr",	OFFSET(t_bootp *,saddr),	&inaddr_resolved_pat,	NULL},
  {"gaddr",	OFFSET(t_bootp *,gaddr),	&inaddr_pat,		NULL},
  {"Gaddr",	OFFSET(t_bootp *,gaddr),	&inaddr_resolved_pat,	NULL},
  {"chaddr",	OFFSET(t_bootp *,chaddr),	&buf_pat,	(VOID_PTR)16},
  {"sname",	OFFSET(t_bootp *,sname),	&buf_pat,	(VOID_PTR)64},
  {"Sname",	OFFSET(t_bootp *,sname),	&sz_pat,	        NULL},
  {"file",	OFFSET(t_bootp *,file),		&buf_pat,      (VOID_PTR)128},
  {"File",	OFFSET(t_bootp *,file),		&sz_pat,	        NULL},
  {"vendor",	OFFSET(t_bootp *,vendor),	&buf_pat,	(VOID_PTR)64},
  {"Magic",	OFFSET(t_bootp *,vendor),  &bufassoc_pat,   &bootp_magic_bad},
  {"Magicbuf",	OFFSET(t_bootp *,vendor),	&buf_pat,	 (VOID_PTR)4},
  NULL_FIELD
};

char				*bootp_itmpl = "\n\
<table _name=bootp[%i%] width=100%%%% bgcolor=\"%%bootpColor%%\">\n\
<tr>\n\
<td align=center width=25%%%%>\n\
<a href=\"set(bootp[%i%].Op)\">%%bootp[%i%].Op%%</a>\n\
(<a href=\"set(bootp[%i%].op)\">%%bootp[%i%].op%%</a>)\n\
</td>\n\
<td align=center width=25%%%%>\n\
<a href=\"set(bootp[%i%].Htype)\">%%bootp[%i%].Htype%%</a>\n\
(<a href=\"set(bootp[%i%].htype)\">%%bootp[%i%].htype%%</a>)\n\
</td>\n\
<td align=center width=25%%%%>\n\
<a href=\"set(bootp[%i%].hlen)\">%%bootp[%i%].hlen%%</a>\n\
</td>\n\
<td align=center width=25%%%%>\n\
<a href=\"set(bootp[%i%].hops)\">%%bootp[%i%].hops%%</a>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].xid)\">%%bootp[%i%].xid%%</a>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=50%%%%>\n\
<a href=\"set(bootp[%i%].secs)\">%%bootp[%i%].secs%%</a>\n\
</td>\n\
<td align=center width=50%%%%>\n\
<a href=\"set(bootp[%i%].unused)\">%%bootp[%i%].unused%%</a>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].Caddr)\">%%bootp[%i%].Caddr%%</a>\n\
(<a href=\"set(bootp[%i%].caddr)\">%%bootp[%i%].caddr%%</a>)\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].Yaddr)\">%%bootp[%i%].Yaddr%%</a>\n\
(<a href=\"set(bootp[%i%].yaddr)\">%%bootp[%i%].yaddr%%</a>)\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].Saddr)\">%%bootp[%i%].Saddr%%</a>\n\
(<a href=\"set(bootp[%i%].saddr)\">%%bootp[%i%].saddr%%</a>)\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].Gaddr)\">%%bootp[%i%].Gaddr%%</a>\n\
(<a href=\"set(bootp[%i%].gaddr)\">%%bootp[%i%].gaddr%%</a>)\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].chaddr)\">%%bootp[%i%].chaddr%%</a>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].Sname)\">%%bootp[%i%].Sname%%</a>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].File)\">%%bootp[%i%].File%%</a>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].vendor)\">%%bootp[%i%].vendor%%</a>\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

char				*bootp_rfc2132_itmpl = "\n\
<table _name=bootp[%i%] width=100%%%% bgcolor=\"%%bootpColor%%\">\n\
<tr>\n\
<td align=center width=25%%%%>\n\
<a href=\"set(bootp[%i%].Op)\">%%bootp[%i%].Op%%</a>\n\
(<a href=\"set(bootp[%i%].op)\">%%bootp[%i%].op%%</a>)\n\
</td>\n\
<td align=center width=25%%%%>\n\
<a href=\"set(bootp[%i%].Htype)\">%%bootp[%i%].Htype%%</a>\n\
(<a href=\"set(bootp[%i%].htype)\">%%bootp[%i%].htype%%</a>)\n\
</td>\n\
<td align=center width=25%%%%>\n\
<a href=\"set(bootp[%i%].hlen)\">%%bootp[%i%].hlen%%</a>\n\
</td>\n\
<td align=center width=25%%%%>\n\
<a href=\"set(bootp[%i%].hops)\">%%bootp[%i%].hops%%</a>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].xid)\">%%bootp[%i%].xid%%</a>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=50%%%%>\n\
<a href=\"set(bootp[%i%].secs)\">%%bootp[%i%].secs%%</a>\n\
</td>\n\
<td align=center width=50%%%%>\n\
<a href=\"set(bootp[%i%].unused)\">%%bootp[%i%].unused%%</a>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].Caddr)\">%%bootp[%i%].Caddr%%</a>\n\
(<a href=\"set(bootp[%i%].caddr)\">%%bootp[%i%].caddr%%</a>)\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].Yaddr)\">%%bootp[%i%].Yaddr%%</a>\n\
(<a href=\"set(bootp[%i%].yaddr)\">%%bootp[%i%].yaddr%%</a>)\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].Saddr)\">%%bootp[%i%].Saddr%%</a>\n\
(<a href=\"set(bootp[%i%].saddr)\">%%bootp[%i%].saddr%%</a>)\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].Gaddr)\">%%bootp[%i%].Gaddr%%</a>\n\
(<a href=\"set(bootp[%i%].gaddr)\">%%bootp[%i%].gaddr%%</a>)\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].chaddr)\">%%bootp[%i%].chaddr%%</a>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].Sname)\">%%bootp[%i%].Sname%%</a>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].File)\">%%bootp[%i%].File%%</a>\n\
</td>\n\
</tr>\n\
<tr>\n\
<td align=center width=100%%%%>\n\
<a href=\"set(bootp[%i%].Magic)\">%%bootp[%i%].Magic%%</a>\n\
(<a href=\"set(bootp[%i%].Magicbuf)\">%%bootp[%i%].Magicbuf%%</a>)\n\
</td>\n\
</tr>\n\
</table>\n\
<br>\n\
";

int	bootp_chan;

PAT_NAME_GENERIC(bootp_pat_name,
		 (VOID_PTR)&bootp_chan,
		 "bootp")

PAT_GET_FIELD_GENERIC(bootp_pat_get_field,
		      bootp_fields)

PAT_SET_FIELD_GENERIC(bootp_pat_set_field,
		      bootp_fields)

PAT_GET_FIELDS_GENERIC(bootp_pat_get_fields,
		       bootp_fields)

PAT_GET_FIELD_PAT_GENERIC(bootp_pat_get_field_pat,
			  bootp_fields)

PAT_GET_TMPL_DECL(bootp_pat_get_tmpl)
{
  if (pat_bootp_do_vendor)
    return (pat_get_itmpl_generic(id,
				  buf,
				  len,
				  str,
				  max_len,
				  (VOID_PTR)&bootp_chan,
				  bootp_rfc2132_itmpl));
  else
    return (pat_get_itmpl_generic(id,
				  buf,
				  len,
				  str,
				  max_len,
				  (VOID_PTR)&bootp_chan,
				  bootp_itmpl));
}
 
PAT_OFF_DECL(bootp_pat_off)
{
  if (pat_bootp_vendor_gt_64)
    (*off_return) = len;
  else
    (*off_return) = BOOTP_HLEN;
  return (0);
}

PAT_SUB_GENERIC(bootp_pat_sub,
		&data_pat)
    
PAT_HAS_OPT_DECL(bootp_pat_has_opt)
{
  t_bootp		*bootp;

  PAT_BOOTP_CHECK(bootp,buf,len);
  if (pat_bootp_do_vendor)
    {
      if (!FBCMP(bootp->vendor,rfc1048_magic,sizeof (rfc1048_magic)))
	{
	  (*has_opt_return) = TRUE;
	  (*opt_off_return) = OFFSET(t_bootp *,vendor) + 4;
	  if (pat_bootp_vendor_gt_64)
	    (*opt_len_return) = len - 300 + 64 - 4;
	  else
	    (*opt_len_return) = 64 - 4;
	  (*opt_pat_return) = &rfc2132opt_pat;
	  return (0);
	}
    }
  (*has_opt_return) = FALSE;
  return (0);
}

t_pat				bootp_pat = 
{
  bootp_pat_name,		/* t_pat_name_proc		*/
  bootp_pat_off,		/* t_pat_off_proc		*/
  bootp_pat_sub,		/* t_pat_sub_proc		*/
  NULL,				/* t_pat_sum_proc		*/
  bootp_pat_get_field,		/* t_pat_get_field_proc		*/
  bootp_pat_set_field,		/* t_pat_set_field_proc		*/
  bootp_pat_get_fields,		/* t_pat_get_fields_proc	*/
  bootp_pat_get_tmpl,		/* t_pat_get_tmpl_proc		*/
  NULL,				/* t_pat_get_tmpl2_proc		*/
  bootp_pat_has_opt,		/* t_pat_has_opt_proc		*/
  NULL,				/* t_pat_adapt_len_proc		*/
  bootp_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	*/
};
