/* print cisco IGRP packets */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <netinet/udp.h>
#include <netinet/udp_var.h>
#include <errno.h>
#include <stdio.h>

#include "interface.h"
#include "addrtoname.h"
#include "igrp.h"

static void
igrp_entry_print(struct igrprte *igr, int is_interior, int is_exterior)
{
    register int delay, bandwidth;
    int metric, mtu;

    if (is_interior)
	printf("\n *.%d.%d.%d", igr->igr_net[0],
	       igr->igr_net[1], igr->igr_net[2]);
    else if (is_exterior)
	printf("\n X%d.%d.%d.0", igr->igr_net[0],
	       igr->igr_net[1], igr->igr_net[2]);
    else
	printf("\n %d.%d.%d.0", igr->igr_net[0],
	       igr->igr_net[1], igr->igr_net[2]);

    delay = ((igr->igr_dly[0] << 16) |
	     (igr->igr_dly[1] << 8) | (igr->igr_dly[2]));
    bandwidth = (igr->igr_bw[0] << 16) |
		(igr->igr_bw[1] << 8) | (igr->igr_bw[2]);
    metric = bandwidth + delay;
    if (metric > 0xffffff)
	metric = 0xffffff;
    mtu = (igr->igr_mtu[0] << 8) | (igr->igr_mtu[1]);

    printf(" d=%d b=%d r=%d l=%d M=%d mtu=%d in %d hops",
	   10*delay, bandwidth == 0 ? 0 : 10000000 / bandwidth,
	   igr->igr_rel, igr->igr_ld, metric,
	   mtu, igr->igr_hct);
    
    return;
}

void
igrp_print(const u_char *chdr, int length, const u_char *cip)
{
    register struct igrphdr *hdr = (struct igrphdr *)chdr;
    register struct ip *ip = (struct ip *)cip;
    register u_char *cp = (u_char *)(hdr + 1);
    register int n;
    int nint, nsys, next;
    char *opcode;

    n = min(length, (u_char *)snapend - cp);

    if (qflag) {
	(void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
		     ipaddr_string(&ip->ip_dst));
	(void)printf(" igrp %d", length);
	return;
    }

    if (!vflag) {
	(void)printf("%s > %s:", ipaddr_string(&ip->ip_src),
		     ipaddr_string(&ip->ip_dst));
	if (n < sizeof(struct igrphdr)) {
	    (void)printf(" truncated-igrp %d", length);
	    return;
	}
	(void)printf(" igrp %d %c (%d)", hdr->ig_as,
		     (hdr->ig_op == IGRP_UPDATE) ? 'U' :
		     ((hdr->ig_op == IGRP_REQUEST) ? 'R' : '?'),
		     length);
	return;
    }

    /* header */

    nint = hdr->ig_ni;
    nsys = hdr->ig_ns;
    next = hdr->ig_nx;

    switch (hdr->ig_op) {
      case IGRP_UPDATE :
	opcode = "Update";
	break;
      case IGRP_REQUEST :
	opcode = "Request";
	break;
      default :
	opcode = "Unknown";
	break;
    }

    (void)printf("\n  %s vers=%d edit=%d AS=%d (%d int / %d sys / %d ext)",
		 opcode, hdr->ig_v, hdr->ig_ed, hdr->ig_as,
		 nint, nsys, next);

    while (n >= IGRP_RTE_SIZE) {
	if (nint > 0) {
	    igrp_entry_print((struct igrprte *)cp, 1, 0);
	    nint--;
	} else if (nsys > 0) {
	    igrp_entry_print((struct igrprte *)cp, 0, 0);
	    nsys--;
	} else if (next > 0) {
	    igrp_entry_print((struct igrprte *)cp, 0, 1);
	    next--;
	} else
	    /* should not happend */
	    break;
	cp += IGRP_RTE_SIZE;
	n -= IGRP_RTE_SIZE;
    }
    if ((nint > 0) || (nsys > 0) || (next > 0))
	(void)printf("\n ...");
}
