/*
 * Public Release 3
 * 
 * $Id: ripng_dump.c,v 1.1.2.3 1998/10/20 19:31:37 swright Exp $
 */

/*
 * ------------------------------------------------------------------------
 * 
 * Copyright (c) 1996, 1997, 1998 The Regents of the University of Michigan
 * All Rights Reserved
 *  
 * Royalty-free licenses to redistribute GateD Release
 * 3 in whole or in part may be obtained by writing to:
 * 
 * 	Merit GateDaemon Project
 * 	4251 Plymouth Road, Suite C
 * 	Ann Arbor, MI 48105
 *  
 * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE REGENTS OF THE
 * UNIVERSITY OF MICHIGAN AND MERIT DO NOT WARRANT THAT THE
 * FUNCTIONS CONTAINED IN THE SOFTWARE WILL MEET LICENSEE'S REQUIREMENTS OR
 * THAT OPERATION WILL BE UNINTERRUPTED OR ERROR FREE. The Regents of the
 * University of Michigan and Merit shall not be liable for
 * any special, indirect, incidental or consequential damages with respect
 * to any claim by Licensee or any third party arising from use of the
 * software. GateDaemon was originated and developed through release 3.0
 * by Cornell University and its collaborators.
 * 
 * Please forward bug fixes, enhancements and questions to the
 * gated mailing list: gated-people@gated.merit.edu.
 * 
 * ------------------------------------------------------------------------
 * 
 * Copyright (c) 1990,1991,1992,1993,1994,1995 by Cornell University.
 *     All rights reserved.
 * 
 * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.
 * 
 * GateD is based on Kirton's EGP and UC Berkeley's routing
 * daemon	 (routed).
 * Development of GateD has been supported in part by the
 * National Science Foundation.
 * 
 * ------------------------------------------------------------------------
 * 
 * Portions of this software may fall under the following
 * copyrights:
 * 
 * Copyright (c) 1988 Regents of the University of California.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms are
 * permitted provided that the above copyright notice and
 * this paragraph are duplicated in all such forms and that
 * any documentation, advertising materials, and other
 * materials related to such distribution and use
 * acknowledge that the software was developed by the
 * University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote
 * products derived from this software without specific
 * prior written permission.  THIS SOFTWARE IS PROVIDED
 * ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#include "include.h"
#include "targets.h"
#include "ripng_internal.h"

static const bits ripng_flag_bits[] = {
    { RIPNGF_ON,	"ON" },
    { RIPNGF_TERMINATE, "Terminate" },
    { RIPNGF_RECONFIG, 	"ReConfig" },
    { 0 }
};

static const bits ripng_target_bits[] = {
    { RIPNGTF_MC,	"Multicast" },
    { RIPNGTF_POLL,	"Poll" },
    { 0 }
};

const bits ripng_cmd_bits[] = {
    { 0,			"Invalid" },
    { RIPNG_COMMAND_REQUEST,	"Request" },
    { RIPNG_COMMAND_RESPONSE,	"Response" },
    { 0 }
};

/*
 *	Dump info about RIPng
 */
static void
ripng_int_dump __PF2(fd, FILE *,
		   list, config_entry *)
{
    register config_entry *cp;

    CONFIG_LIST(cp, list) {
	switch (cp->config_type) {
	case RIPNG_CONFIG_IN:
	    (void) fprintf(fd, " %sripin",
			   GA2S(cp->config_data) ? "" : "no");
	    break;

	case RIPNG_CONFIG_OUT:
	    (void) fprintf(fd, " %sripout",
			   GA2S(cp->config_data) ? "" : "no");
	    break;

	case RIPNG_CONFIG_METRICIN:
	    (void) fprintf(fd, " metricin %u",
			   (metric_t) GA2S(cp->config_data));
	    break;

	case RIPNG_CONFIG_METRICOUT:
	    (void) fprintf(fd, " metricout %u",
			   (metric_t) GA2S(cp->config_data));
	    break;

	default:
	    assert(FALSE);
	    break;
	}
    } CONFIG_LIST_END(cp, list) ;
}

void
ripng_dump __PF2(tp, task *,
		 fd, FILE *)
{
    (void) fprintf(fd, "\tFlags: %s\t\tDefault preference: %d\n",
		   trace_bits(ripng_flag_bits, ripng_flags),
		   ripng_preference);
    target_dump(fd, &ripng_targets, ripng_target_bits);
    if (ripng_gw_list) {
	(void) fprintf(fd, "\tActive gateways:\n");
	gw_dump(fd,
		"\t\t",
		ripng_gw_list,
		tp->task_rtproto);
	(void) fprintf(fd, "\n");
    }
    if (ripng_int_policy) {
	(void) fprintf(fd, "\tInterface policy:\n");
	control_interface_dump(fd, 2, ripng_int_policy, ripng_int_dump);
    }
    control_import_dump(fd,1, RTPROTO_RIPNG, ripng_import_list, ripng_gw_list);
    control_export_dump(fd,1, RTPROTO_RIPNG, ripng_export_list, ripng_gw_list);
    (void) fprintf(fd, "\n");
}

void
ripng_trace __PF7(trp, trace *,
		  dir, int,
		  ifap, if_addr *,
		  who, sockaddr_un *,
		  msg, register struct ripng *,
		  size, register size_t,
		  detail, int)
{
    register int printed;
    register const char *cmd = trace_state(ripng_cmd_bits, msg->ripng_command < RIPNG_COMMAND_MAX ? msg->ripng_command : 0);
    if (dir) {
	/* Trace packet transmission */

	tracef("RIPng %sSENT %A(%s) -> %#A",
	       dir > 0 ? "" : "*NOT* ",
	       ifap->ifa_addr_local,
               ifap->ifa_link->ifl_name,
	       who);
    } else {
	/* Trace packet reception */
	tracef("RIPng RECV %#A",
	       who);
	if (task_recv_dstaddr) {
	    tracef(" -> %A",
		   task_recv_dstaddr);
	}
	if (task_recv_interface) {
	    tracef(" interface %s(%A)",
		   task_recv_interface->ifa_link->ifl_name,
		   task_recv_interface->ifa_addr_local);
	}
    }
    tracef(" version %d,  command %s, length %d",
	   msg->ripng_version,
	   cmd,
	   size);

    switch(msg->ripng_version) {
      case RIPNG_VERSION_1:
	{
	    if (msg->ripng_null16) {
		tracef(" ?");
	    }

	    trace_only_tf(trp,
			  0,
			  (NULL));	/* flush the trace */

	    if (detail) {
		struct ripng_netinfo *rte = (struct ripng_netinfo *) ((void_t) (msg + 1));

		printed = 0;
		for (size -= sizeof(struct ripng);
		     size >= sizeof(struct ripng_netinfo);
		     rte++, size -= sizeof(struct ripng_netinfo)) {

		    char zero = ' ';

		    if (rte->ripng_metric == RIPNG_METRIC_NEXTHOP) {
#define rtn ((struct ripng_nexthop *)rte)
			/* Verify that all reserved fields are zero */
			if (rtn->ripng_null16
			    || rtn->ripng_null8) {
			    zero = '?';
			}

			tracef("\tNext Hop of the belows are %A",
			       sockbuild_in6(0, (byte *)&rtn->ripng_nexthop));
			printed++;
#undef rtn
		    } else {
			/* Verify that all reserved fields are zero */
			if (rte->ripng_tag) {
			    zero = '?';
			}
			tracef("\t%A/%d metric %d%s",
			       sockbuild_in6(0, (byte *)&rte->ripng_prefix),
			       rte->ripng_prefixlen,
			       rte->ripng_metric,
			       (rte->ripng_metric > 16) ? "(???)" : "");
			printed++;
		    }
		    if (printed == 2) {
		        trace_only_tf(trp,
				      0,
				      (NULL));
			printed = 0;
		    }
		}
	    }
	    trace_only_tf(trp,
			  TRC_NOSTAMP,
			  (NULL));
	}
	break;

      default:
	{
	    trace_only_tf(trp,
			  0,
			  (NULL));
	    break;
	}
    }
}

void
ripng_tsi_dump __PF4(fp, FILE *,
		     rth, rt_head *,
		     data, void_t,
		     pfx, const char *)
{
    target *tlp = (target *) data;
    td_entry *tdp;

    TD_TSI_GET(tlp, rth, tdp);

    if (tdp) {
	(void) fprintf(fp,
		       "%sRIPng %A%s <%s> metric %u\n",
			pfx,
			*tlp->target_dst,
			BIT_TEST(tlp->target_flags, RIPNGTF_MC) ? "(mc)" : "",
			trace_bits(target_entry_bits, tdp->td_flags),
			tdp->td_metric);
    }
}
