/* 
 * $Id: idrp_ps_print.c,v 1.3 1995/08/01 20:26:01 sjr Exp $
 * Merit IDRP release 1.1 (gated 3.5.4).  Copyright (c) 1994 by Merit Network, Inc. 
 */

/*
 *  idrp_ps_print.c -- sjr
 *
 *  Function for printing out IDRP's ps (process-specific) data.
 */

#include "include.h"
#include "idrp.h"
#include "idrp_policy.h"
#include <stdio.h>

#define IDRP_PS_PRINT_HEADER "\
IDRP protocol-specific information (ps_flag = %lx)\n\n\
"

char s[128];

/* p_snpa is of type "struct _snpa_entry *" */
#define idrp_print_snpa(p_snpa) ((char *)sprintf(s, "\tstruct _snpa_entry:\n\n\t\tlen = %u\n\t\tsnpa = %lu\n", \
		p_snpa->len, p_snpa->snpa))


/* qos_name is of type "char *"; qos, of type "qos_operator" */

#define idrp_print_qos(qos_name, qos) ((char *) sprintf(s, "\t%s %s %lu\n", \
		qos_name, \
		(qos).operator > -1 ? char_qos_operators[(qos).operator] : "<no op!>", \
		(qos).value))

/* addr is of type "struct iso_net_addr" */
#define idrp_print_iso_net_addr(addr) ((char *) sprintf(s, \
"\tstruct iso_net_addr:\n\t\tisoa_len = %u\n\t\tisoa_family = %u\n\t\tisoa_genaddr = \"%s\"\n", \
		addr.isoa_len, addr.isoa_family, addr.isoa_genaddr))

/* intf is of type "sockaddr_un *" */
#define idrp_print_ip_intf(intf) ((char *) sprintf(s, \
"\tIP intf (sockaddr_un *):\n\t\tsin_len = %u\n\t\tsin_family = %u\n\t\tsin_port = %d\n\t\tsin_addr.saddr = %lu\n", \
		intf->in.sin_len, intf->in.sin_family, intf->in.sin_port, intf->in.sin_addr.s_addr))

char *
idrp_ps_print __PF2(adv_ps_field, void *,
		doit, int)
{
	static char 	 buf[4096];
	char  	*s;
	u_int	 i;
	idrp_ps_t *p_idrp_ps;
	struct  _idrp_canon_rdpath *p_rd;
	struct  _snpa_entry *p_snpa;

	s = buf;
	p_idrp_ps = (idrp_ps_t *) adv_ps_field;
	if (!doit)
		return ("[doit is FALSE]");
	else 
	{ 
		(void) sprintf(buf, IDRP_PS_PRINT_HEADER, p_idrp_ps->ps_flag);
		switch (p_idrp_ps->ps_flag & IDRP_PSFT_TYPE) 
		{
			case (IDRP_PSFT_RIBID):
				(void) sprintf(s + strlen(buf) - 1, 
					"\tps_rib_id = %d\n", 
					p_idrp_ps->ps_rib_id);
				break;

			case (IDRP_PSFT_NEXTHOP_SNPA):
				(void) strcat(buf, "NEXT_HOP information (SNPA list):\n");

				SNPA_LIST(i, p_snpa, (*p_idrp_ps->ps_nexthop_snpas)) {
					/* @@@ (void) strcat(buf, idrp_print_snpa(p_snpa));*/
				} SNPA_LIST_END
				break;

			case (IDRP_PSFT_NEXTHOP_NET):
				(void) strcat(buf, "NEXT_HOP information (ISO net addr):\n");
				(void) strcat(buf, idrp_print_iso_net_addr((*p_idrp_ps->ps_nexthop_net)));
				break;

			case (IDRP_PSFT_NEXTHOP_IPGW):
				(void) strcat(buf, "NEXT_HOP information (IP gateway):\n");
				(void) strcat(buf, idrp_print_ip_intf(p_idrp_ps->ps_gw));
				break;

			case (IDRP_PSFT_NEXTHOP_IPINTF):
				(void) strcat(buf, "NEXT_HOP information (IP interface):\n");
				(void) strcat(buf, idrp_print_ip_intf(p_idrp_ps->ps_intf));
				break;

			case (IDRP_PSFT_ROUTESERV):
				if (BIT_SET(p_idrp_ps->ps_flag, IDRP_PSFT_RESTRICT)) { 
				(void) sprintf(s + strlen(buf) - 1, 
					"\t(routes with route server restricted)\n"); 
				} else {
				(void) sprintf(s + strlen(buf) - 1, 
					"\t(routes with route server OK)\n"); 
				}
				break;

			case (IDRP_PSFT_MULTIEXIT):
			        if (p_idrp_ps->ps_multi_exit) {
				(void) strcat(buf, idrp_print_qos("multiexit", *p_idrp_ps->ps_multi_exit));
			        } else {
				if (BIT_SET(p_idrp_ps->ps_flag, IDRP_PSFT_RESTRICT)) { 
				(void) sprintf(s + strlen(buf) - 1, 
					"\t(routes with external info restricted)\n"); 
				} else {
				(void) sprintf(s + strlen(buf) - 1, 
					"\t(routes with external info OK)\n"); 
				}
			        }
				break;

			case (IDRP_PSFT_CAPACITY):
				(void) strcat(buf, idrp_print_qos("capacity", *p_idrp_ps->ps_capacity));
				break;

			case (IDRP_PSFT_HOPCNT):
				(void) sprintf(s + strlen(buf) - 1, 
					"\tps_hopcnt_pref = %d\n", 
					p_idrp_ps->ps_hopcnt_pref);
				break;

			case (IDRP_PSFT_EXTINFO):
				if (BIT_SET(p_idrp_ps->ps_flag, IDRP_PSFT_RESTRICT)) { 
				(void) sprintf(s + strlen(buf) - 1, 
					"\t(routes with external info restricted)\n"); 
				} else {
				(void) sprintf(s + strlen(buf) - 1, 
					"\t(routes with external info OK)\n"); 
				}
				break;

			case (IDRP_PSFT_DISTINCL):
				(void) strcat(buf, "DIST_LIST_INCLUDE:\n");

				RDPATH_LIST(p_idrp_ps->ps_dist_list_incl, p_rd) {
					(void) strcat(buf, idrp_print_iso_net_addr(p_rd->p_rdi->rdi));
				} RDPATH_LIST_END
				break;

			case (IDRP_PSFT_DISTEXCL):
				(void) strcat(buf, "DIST_LIST_EXCLUDE:\n");

				RDPATH_LIST(p_idrp_ps->ps_dist_list_excl, p_rd) {
					(void) strcat(buf, idrp_print_iso_net_addr(p_rd->p_rdi->rdi));
				} RDPATH_LIST_END
				break;

			case (IDRP_PSFT_DISTATT):
				(void) strcat(buf, "Distinguishing Attributes:\n");
				(void) sprintf(s + strlen(buf) - 1, 
					"\trib_id = %d, idrp_mask = %u\n",
					p_idrp_ps->ps_qos->rib_id,
					p_idrp_ps->ps_qos->idrp_mask);
				(void) strcat(buf, idrp_print_qos("delay", p_idrp_ps->ps_qos->delay));
				(void) strcat(buf, idrp_print_qos("error", p_idrp_ps->ps_qos->error));
				(void) strcat(buf, idrp_print_qos("expense", p_idrp_ps->ps_qos->expense));
				(void) strcat(buf, idrp_print_qos("priority", p_idrp_ps->ps_qos->priority));
				break;

			case (IDRP_PSFT_HIERARCH):
				(void) sprintf(s + strlen(buf) - 1, 
					"\tps_status = %x ps_hierarch_rec = %u\n", 
					p_idrp_ps->ps_status, (p_idrp_ps->ps_status & IDRP_OPTS_HIER_REC));
				break;

			default:
				assert(FALSE);
		}
	}

	return (buf);
}

