view usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_mip.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
line wrap: on
line source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (the "License").  You may not use this file except in compliance
 * with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"@(#)snoop_mip.c	1.5	05/08/23 SMI"

#include <stdio.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <protocols/routed.h>
#include <string.h>
#include <arpa/inet.h>
#include "snoop.h"
#include "snoop_mip.h"

/*
 * This defines the length of internal, unbounded buffers. We set
 * this to be MAXLINE (the maximum verbose display line length) -
 * 64, which should be enough for all necessary descriptions.
 */
#define	BUFLEN	MAXLINE - 64

extern char *dlc_header;
extern char *addrtoname();

enum EXT_TYPE { ADV, REG };

/*
 * This defines the interface for all extention interpreter
 * functions. The function will be called with following
 * parameters:
 *
 * type:	IN	The type code for this extention
 * len		IN	The length of the payload (i.e. the
 *			length field in an extension header)
 * payload	IN	A pointer to the beginning of the
 *			extension payload
 */
typedef void interpreter_f(uint8_t type, uint8_t len, uchar_t *payload);

struct ext_dispatch {
	uint8_t type;
	interpreter_f *pfunc;
};

/* Description structure -- maps type to description */
struct ext_desc {
	uint8_t type;
	const char *desc;
};

/*
 * Interpreter function prototypes for both adv and reg. These
 * all must implement the interpret_f interface defined above.
 */
static void spi_ext(uint8_t, uint8_t, uchar_t *);
static void key_ext(uint8_t, uint8_t, uchar_t *);
static void trav_ext(uint8_t, uint8_t, uchar_t *);
static void empty_ext(uint8_t, uint8_t, uchar_t *);
static void nai_ext(uint8_t, uint8_t, uchar_t *);
static void chall_ext(uint8_t, uint8_t, uchar_t *);
static void ma_ext(uint8_t, uint8_t, uchar_t *);
static void prefix_ext(uint8_t, uint8_t, uchar_t *);
static void unk_ext(uint8_t, uint8_t, uchar_t *);

/* R E G I S T R A T I O N */

#define	REG_TBL_LEN	10	/* update this when adding to the table */

/* Reg: type to description mapping table */
static struct ext_desc reg_desc[] = {
	MN_HA_AUTH,	"(Mobile-Home Authentication Extension)",
	MN_FA_AUTH,	"(Mobile-Foreign Authentication Extension",
	FA_HA_AUTH,	"(Foreign-Home Authentication Extension)",
	GEN_AUTH,	"(Generalized Authentication Extension)",
	MN_HA_KEY,	"(Mobile-Home Key Extension)",
	MN_FA_KEY,	"(Mobile-Foreign Key Extension)",
	MN_HA_TRAVERSE,	"(Firewall Traversal Extension)",
	ENCAP_DELIV,	"(Encapsulating Delivery Style Extension)",
	MN_NAI,		"(Mobile Node Network Access Identifier)",
	FA_CHALLENGE,	"(Mobile-Foreign Agent Challenge)",
	0,		"(Unrecognized Extension)"
};

#define	GENAUTH_TBL_LEN	1	/* update this when adding to the table */

/* Subtypes for Generic Authentication Extension type (type 36) */
static struct ext_desc genauth_desc[] = {
	GEN_AUTH_MN_AAA,	"(MN-AAA Authentication Subtype)",
	0,			"(Unrecognized Subtype)"
};

/* Reg: type to function mapping table */
static struct ext_dispatch reg_dispatch[] = {
	MN_HA_AUTH,	spi_ext,
	MN_FA_AUTH,	spi_ext,
	FA_HA_AUTH,	spi_ext,
	GEN_AUTH,	spi_ext,
	MN_HA_KEY,	key_ext,
	MN_FA_KEY,	key_ext,
	MN_HA_TRAVERSE,	trav_ext,
	ENCAP_DELIV,	empty_ext,
	MN_NAI,		nai_ext,
	FA_CHALLENGE,	chall_ext,
	0,		unk_ext
};

/* A D V E R T I S E M E N T */

#define	ADV_TBL_LEN	5	/* update this when adding to the table */

/* Adv: type to description mapping table */
static struct ext_desc adv_desc[] = {
	ICMP_ADV_MSG_PADDING_EXT,	"(Padding)",
	ICMP_ADV_MSG_MOBILITY_AGT_EXT,	"(Mobility Agent Extension)",
	ICMP_ADV_MSG_PREFIX_LENGTH_EXT,	"(Prefix Lengths)",
	ICMP_ADV_MSG_FA_CHALLENGE,	"(Foreign Agent Challenge)",
	ICMP_ADV_MSG_FA_NAI,		"(Foreign Agent NAI)",
	0,				"(Unrecognized Extension)"
};

/* Adv: type to function mapping table */
static struct ext_dispatch adv_dispatch[] = {
	ICMP_ADV_MSG_PADDING_EXT,	NULL,	/* never called */
	ICMP_ADV_MSG_MOBILITY_AGT_EXT,	ma_ext,
	ICMP_ADV_MSG_PREFIX_LENGTH_EXT,	prefix_ext,
	ICMP_ADV_MSG_FA_CHALLENGE,	chall_ext,
	ICMP_ADV_MSG_FA_NAI,		nai_ext,
	0,				unk_ext
};

#define	GETSPI(payload, hi, low) \
	(void) memcpy(&hi, payload, sizeof (hi)); \
	(void) memcpy(&low, payload + sizeof (hi), sizeof (low))

static void dumphex(uchar_t *payload, int payload_len, char *buf, char *msg) {
	int index;

	for (index = 0; index < payload_len; index++) {
		(void) sprintf(&buf[index * 3], " %.2x", payload[index]);
	}

	(void) sprintf(get_line((char *)payload-dlc_header, 1), msg, buf);
}

static const char *get_desc(struct ext_desc table[], uint8_t type, int max) {
	int i;

	for (i = 0; i < max && table[i].type != type; i++)
	    /* NO_OP */;

	return (table[i].desc);
}

/*
 * The following is an accessor for the description table, used by
 * snoop_icmp.c. This maintains the encapsulation of the internal
 * description table.
 */
const char *get_mip_adv_desc(uint8_t type) {
	return (get_desc(adv_desc, type, ADV_TBL_LEN));
}

static interpreter_f *get_interpreter(struct ext_dispatch table[],
				uint8_t type,
				int max) {
	int i;

	for (i = 0; i < max && table[i].type != type; i++)
	    /* NO_OP */;

	return (table[i].pfunc);
}

static int
interpret_extensions(uchar_t *ext,
			int regext_size,
			enum EXT_TYPE etype) {

	int curr_size  =  regext_size; /* remaining total for all exts */
	exthdr_t *exthdr;
	gen_exthdr_t *gen_exthdr;
	const char *st;
	uchar_t	*p;
	interpreter_f *f;
	uint8_t	ext_type;
	uint16_t ext_len;
	uint_t ext_hdrlen;

	show_space();
	exthdr = (exthdr_t *)ALIGN(ext);


	do {
	    ext_type = exthdr->type;
	    if (ext_type == GEN_AUTH) {
		gen_exthdr = (gen_exthdr_t *)exthdr;
		ext_hdrlen = sizeof (gen_exthdr_t);
		ext_len = ntohs(gen_exthdr->length);
	    } else {
		ext_hdrlen = sizeof (exthdr_t);
		ext_len = exthdr->length;
	    }

	    if (!((etype == ADV && ext_type == ICMP_ADV_MSG_PADDING_EXT &&
		curr_size >= 1) ||
		curr_size >= ext_hdrlen + ext_len))
		    break;

	    /* Print description for this extension */
	    if (etype == ADV) {
		st = get_desc(adv_desc, ext_type, ADV_TBL_LEN);
	    } else /* REG */ {
		st = get_desc(reg_desc, ext_type, REG_TBL_LEN);
	    }

	    (void) sprintf(get_line((char *)exthdr-dlc_header, 1),
			"Extension header type = %d  %s", ext_type, st);

	    if (ext_type == GEN_AUTH) {
		st = get_desc(genauth_desc, gen_exthdr->subtype,
		    GENAUTH_TBL_LEN);
		(void) sprintf(get_line((char *)exthdr-dlc_header, 1),
		    "Subtype = %d %s", gen_exthdr->subtype, st);
	    }

	    /* Special case for 1-byte padding */
	    if (etype == ADV && ext_type == ICMP_ADV_MSG_PADDING_EXT) {
		exthdr = (exthdr_t *)((uchar_t *)exthdr + 1);
		curr_size--;
		continue;
	    }

	    (void) sprintf(get_line((char *)&exthdr->length-dlc_header, 1),
			"Length = %d", ext_len);

	    /* Parse out the extension's payload */
	    p = (uchar_t *)exthdr + ext_hdrlen;
	    curr_size -= (ext_hdrlen + ext_len);

	    if (etype == ADV) {
		f = get_interpreter(adv_dispatch, ext_type, ADV_TBL_LEN);
	    } else /* REG */ {
		f = get_interpreter(reg_dispatch, ext_type, REG_TBL_LEN);
	    }

	    f(ext_type, ext_len, p);

	    show_space();
	    exthdr = (exthdr_t *)(p + ext_len);
	} while (B_TRUE);

	return (0);
}

void interpret_icmp_mip_ext(uchar_t *p, int len) {
	show_space();
	show_header("ICMP:  ", " MIP Advertisement Extensions ", len);
	show_space();

	interpret_extensions(p, len, ADV);
}

void
interpret_mip_cntrlmsg(int flags, uchar_t *msg, int fraglen) {
	char		*pt, *pc = NULL;
	char		*line;
	regreq_t	rreq[1];
	regrep_t	rrep[1];
	int		regext_size;
	uchar_t		*regext_data;
	struct in_addr	addr_temp;


	/* First byte of the message should be the type */
	switch (*msg) {
	case REG_TYPE_REQ:
		if (fraglen < sizeof (regreq_t))
			return;
		pt = (flags & F_DTAIL ? "registration request ":"reg rqst ");

		(void) memcpy(rreq, msg, sizeof (*rreq));
		regext_size = fraglen - sizeof (regreq_t);
		regext_data = msg + sizeof (*rreq);
		break;
	case REG_TYPE_REP:
		if (fraglen < sizeof (regrep_t))
			return;
		pt = (flags & F_DTAIL ? "registration reply ":"reg reply ");

		(void) memcpy(rrep, msg, sizeof (*rrep));
		regext_size = fraglen - sizeof (regrep_t);
		regext_data = msg + sizeof (*rrep);

		switch (rrep->code) {
		case  REPLY_CODE_ACK:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL)) ?
			    "OK" : "OK code 0";
			break;
		case  REPLY_CODE_ACK_NO_SIMULTANEOUS:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "OK simultaneous bindings" : "OK code 1";
			break;
		case  REPLY_CODE_FA_NACK_UNSPECIFIED:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: unspecified":"FA denial: code 64";
			break;
		case  REPLY_CODE_FA_NACK_PROHIBITED:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: prohibited":"FA denial: code 65";
			break;
		case  REPLY_CODE_FA_NACK_RESOURCES:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: no resources":"FA denial: code 66";
			break;
		case  REPLY_CODE_FA_NACK_MN_AUTH:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: MN auth failed":"FA denial: code 67";
			break;
		case  REPLY_CODE_FA_NACK_HA_AUTH:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: HA auth failed":
			    "FA denial: code 68";
			break;
		case  REPLY_CODE_FA_NACK_LIFETIME:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: lifetime":"FA denial: code 69";
			break;
		case  REPLY_CODE_FA_NACK_BAD_REQUEST:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: bad request": "FA: code 70";
			break;
		case  REPLY_CODE_FA_NACK_BAD_REPLY:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: bad Reply":"FA denial: code 71";
			break;
		case  REPLY_CODE_FA_NACK_ENCAP_UNAVAILABLE:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: encapsulation":"FA denial: code 72";
			break;
		case  REPLY_CODE_FA_NACK_VJ_UNAVAILABLE:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: VJ compression":"FA denial: code 73";
			break;
		case  REPLY_CODE_FA_NACK_BIDIR_TUNNEL_UNAVAILABLE:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: reverse tunnel unavailable":
				"FA denial: code 74";
			break;
		case  REPLY_CODE_FA_NACK_BIDIR_TUNNEL_NO_TBIT:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: reverse tunnel: missing T-bit":
				"FA denial: code 75";
			break;
		case  REPLY_CODE_FA_NACK_BIDIR_TUNNEL_TOO_DISTANT:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: reverse tunnel: too distant":
				"FA denial: code 76";
			break;
		case  REPLY_CODE_FA_NACK_ICMP_HA_NET_UNREACHABLE:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: home network unreachable":
			    "FA denial: code 80";
			break;
		case  REPLY_CODE_FA_NACK_ICMP_HA_HOST_UNREACHABLE:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: HA host unreachable":
			    "FA denial: code 81";
			break;
		case  REPLY_CODE_FA_NACK_ICMP_HA_PORT_UNREACHABLE:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: HA port unreachable":
			    "FA denial: code 82";
			break;
		case  REPLY_CODE_FA_NACK_ICMP_HA_UNREACHABLE:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: HA unreachable":"FA denial: code 88";
			break;
		case REPLY_CODE_FA_NACK_UNIQUE_HOMEADDR_REQD:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: Unique Home Addr Required":
				"FA denial: code 96";
			break;
		case REPLY_CODE_FA_NACK_MISSING_NAI:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: Missing NAI":
				"FA denial: code 97";
			break;
		case REPLY_CODE_FA_NACK_MISSING_HOME_AGENT:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: Missing Home Agent":
				"FA denial: code 98";
			break;
		case REPLY_CODE_FA_NACK_UNKNOWN_CHALLENGE:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: Unknown Challenge":
				"FA denial: code 104";
			break;
		case REPLY_CODE_FA_NACK_MISSING_CHALLENGE:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: Missing Challenge":
				"FA denial: code 105";
			break;
		case REPLY_CODE_FA_NACK_MISSING_MN_FA:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "FA denial: Missing Mobile-Foreign Key Extension":
				"FA denial: code 106";
			break;
		case  REPLY_CODE_HA_NACK_UNSPECIFIED:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "HA denial: unspecified":"HA denial: code 128";
			break;
		case  REPLY_CODE_HA_NACK_PROHIBITED:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "HA denial: prohibited":"HA denial: code 129";
			break;
		case  REPLY_CODE_HA_NACK_RESOURCES:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "HA denial: no resources":"HA denial: code 130";
			break;
		case  REPLY_CODE_HA_NACK_MN_AUTH:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "HA denial: MN auth failed":"HA denial: code 131";
			break;
		case  REPLY_CODE_HA_NACK_FA_AUTH:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "HA denial: FA auth failed":"HA denial: code 132";
			break;
		case  REPLY_CODE_HA_NACK_ID_MISMATCH:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "HA denial: ID mismatch":"HA denial: code 133";
			break;
		case  REPLY_CODE_HA_NACK_BAD_REQUEST:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "HA denial: bad request":"HA denial: code 134";
			break;
		case  REPLY_CODE_HA_NACK_TOO_MANY_BINDINGS:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "HA denial: too many bindings":
			    "HA denial: code 135";
			break;
		case  REPLY_CODE_HA_NACK_BAD_HA_ADDRESS:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "HA denial: bad HA address":"HA denial: code 136";
			break;
		case  REPLY_CODE_HA_NACK_BIDIR_TUNNEL_UNAVAILABLE:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "HA denial: no reverse tunnel":
			    "HA denial: code 137";
			break;
		case  REPLY_CODE_HA_NACK_BIDIR_TUNNEL_NO_TBIT:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "HA denial: reverse tunnel: no T-bit":
			    "HA denial: code 138";
			break;
		case  REPLY_CODE_HA_NACK_BIDIR_ENCAP_UNAVAILABLE:
			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
			    "HA denial: encapsulation unavailable":
			    "HA denial: code 139";
			break;
		default:
			pc = "?";
			break;
		}
		break;

	default :
		break;
	}
	if (flags & F_SUM) {
		line = get_sum_line();

		if (pc != NULL)
			(void) sprintf(line, "Mobile IP %s(%s)", pt, pc);
		else
			(void) sprintf(line, "Mobile IP %s", pt);
	}

	if (flags & F_DTAIL) {
		show_header("MIP:  ", "Mobile IP Header", fraglen);
		show_space();

		if (*msg == REG_TYPE_REQ) {
			(void) sprintf(get_line((char *)&rreq -
			    dlc_header, 1), "Registration header type = %s",
			    pt);
			(void) sprintf(get_line(
			    (char *)(((uchar_t *)&rreq) + 1) - dlc_header, 1),
			    "%d... .... = %s simultaneous bindings  ",
			    (rreq->Simultaneous_registration == 1)? 1 : 0,
			    (rreq->Simultaneous_registration == 1)? "":"no");
			(void) sprintf(get_line(
			    (char *)(((uchar_t *)&rreq) + 1) - dlc_header, 1),
			    ".%d.. .... = %s broadcast datagrams ",
			    (rreq->Broadcasts_desired == 1) ?  1 : 0,
			    (rreq->Broadcasts_desired == 1) ? "":"no");
			(void) sprintf(get_line(
			    (char *)(((uchar_t *)&rreq) + 1) - dlc_header, 1),
			    "..%d. .... = %s decapsulation by MN",
			    (rreq->Decapsulation_done_locally == 1) ? 1 : 0,
			    (rreq->Decapsulation_done_locally == 1) ?
				"" : "no");
			(void) sprintf(get_line(
			    (char *)(((uchar_t *)&rreq) + 1) - dlc_header, 1),
			    "...%d .... = %s minimum encapsulation ",
			    (rreq->Minimal_encap_desired == 1) ? 1 : 0,
			    (rreq->Minimal_encap_desired == 1) ? "" : "no");
			(void) sprintf(get_line(
			    (char *)(((uchar_t *)&rreq) + 1) - dlc_header, 1),
			    ".... %d... = %s GRE encapsulation ",
			    (rreq->GRE_encap_desired == 1) ? 1 : 0,
			    (rreq->GRE_encap_desired == 1) ? "" : "no");
			(void) sprintf(get_line(
			    (char *)(((uchar_t *)&rreq) + 1) - dlc_header, 1),
			    ".... .%d.. = %s VJ hdr Compression ",
			    (rreq->VJ_compression_desired == 1) ? 1 : 0,
			    (rreq->VJ_compression_desired == 1) ? "" : "no");
			(void) sprintf(get_line(
			    (char *)(((uchar_t *)&rreq) + 1) - dlc_header, 1),
			    ".... ..%d. = %s reverse tunnel",
			    (rreq->BiDirectional_Tunnel_desired == 1) ? 1 : 0,
			    (rreq->BiDirectional_Tunnel_desired == 1) ?
				"" : "no");
			if (ntohs(rreq->lifetime) == 0xffff) {
				(void) sprintf(get_line(
				    (char *)&rreq->lifetime - dlc_header, 1),
				    "Life Time = 0xFFFF (infinity)");
			} else if (ntohs(rreq->lifetime) == 0) {
				(void) sprintf(get_line(
				    (char *)&rreq->lifetime - dlc_header, 1),
				    "Life Time = 0 "
				    "(request for de-registration)");
			} else {
				(void) sprintf(get_line(
				    (char *)&rreq->lifetime - dlc_header, 1),
				    "Life time = %d seconds",
				    ntohs(rreq->lifetime));
			}
			addr_temp.s_addr = rreq->home_addr;
			(void) sprintf(get_line(
			    (char *)&rreq->home_addr - dlc_header, 1),
			    "Home address = %s, %s",
			    inet_ntoa(addr_temp),
			    addrtoname(AF_INET, &addr_temp));
			addr_temp.s_addr = rreq->home_agent_addr;
			(void) sprintf(get_line(
			    (char *)&rreq->home_agent_addr - dlc_header, 1),
			    "Home Agent address = %s, %s",
			    inet_ntoa(addr_temp),
			    addrtoname(AF_INET, &addr_temp));
			addr_temp.s_addr = rreq->care_of_addr;
			(void) sprintf(get_line(
			    (char *)&rreq->care_of_addr - dlc_header, 1),
			    "Care of address = %s, %s",
			    inet_ntoa(addr_temp),
			    addrtoname(AF_INET, &addr_temp));
			(void) sprintf(get_line(
			    (char *)&rreq->identification - dlc_header, 1),
			    "Identification = 0x%x-%x",
			    ntohl(rreq->identification.high_bits),
			    ntohl(rreq->identification.low_bits));
		} else if (*msg == REG_TYPE_REP) {
			(void) sprintf(
			    get_line((char *)&rrep->type - dlc_header, 1),
			    "Registration header type = %d (%s)",
			    (int)rrep->type, pt);
			(void) sprintf(get_line((char *)&rrep - dlc_header, 1),
			    "Code = %d %s", (int)rrep->code, pc);
			if (ntohs(rrep->lifetime) == 0xffff) {
				(void) sprintf(get_line(
				    (char *)&rrep->lifetime - dlc_header, 1),
				    "Life time = 0xFFFF (infinity)");
			} else if (ntohs(rrep->lifetime) == 0) {
				(void) sprintf(get_line(
				    (char *)&rrep->lifetime - dlc_header, 1),
				    ((rrep->code == REPLY_CODE_ACK) ||
				    (rrep->code ==
					REPLY_CODE_ACK_NO_SIMULTANEOUS))?
				    "Life time = 0 (de-registeration success)" :
				    "Life time = 0 (de-registration failed)");
			} else {
				(void) sprintf(get_line(
				    (char *)&rrep->lifetime - dlc_header, 1),
				    "Life time = %d seconds",
				    ntohs(rrep->lifetime));
			}
			addr_temp.s_addr = rrep->home_addr;
			(void) sprintf(
			    get_line((char *)&rrep->home_addr - dlc_header, 1),
			    "Home address = %s, %s",
			    inet_ntoa(addr_temp),
			    addrtoname(AF_INET, &addr_temp));
			addr_temp.s_addr = rrep->home_agent_addr;
			(void) sprintf(get_line(
			    (char *)&rrep->home_agent_addr - dlc_header, 1),
			    "Home Agent address = %s, %s",
			    inet_ntoa(addr_temp),
			    addrtoname(AF_INET, &addr_temp));
			(void) sprintf(get_line(
			    (char *)&rrep->identification - dlc_header, 1),
			    "Identification = 0x%x-%x",
			    ntohl(rrep->identification.high_bits),
			    ntohl(rrep->identification.low_bits));
		}
		fraglen = interpret_extensions(regext_data, regext_size, REG);
	}
}

/*ARGSUSED*/
static void spi_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
	uint16_t spi_hi, spi_low;
	char	auth_prn_str[BUFLEN];

	/* SPI */
	GETSPI(p, spi_hi, spi_low);
	(void) sprintf(get_line((char *)p - dlc_header, 1),
			"Security Parameter Index = 0x%x%x",
			ntohs(spi_hi), ntohs(spi_low));
	p += sizeof (spi_hi) + sizeof (spi_low);
	this_ext_len -= sizeof (spi_hi) + sizeof (spi_low);

	/* The rest is the authenticator; dump it in hex */
	dumphex(p,
		/* don't write past our string buffer ... */
		(this_ext_len*3 > BUFLEN ? BUFLEN : this_ext_len),
		auth_prn_str,
		"Authenticator = %s");
}

static void key_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
	uint16_t alg, spi_hi, spi_low;
	char *alg_string;
	char *hafa = (type == MN_HA_KEY ? "HA" : "FA");
	char sec_msg[32];
	char auth_prn_str[BUFLEN];

	/* Algorithm Type */
	(void) memcpy(&alg, p, sizeof (alg));
	alg = ntohs(alg);
	switch (alg) {
	case KEY_ALG_NONE:
	    alg_string = "None";
	    break;
	case SA_MD5_MODE_PREF_SUF:
	    alg_string = "MD5/prefix+suffix";
	    break;
	case SA_HMAC_MD5:
	    alg_string = "HMAC MD5";
	    break;
	default:
	    alg_string = "Unknown";
	    break;
	}
	(void) sprintf(get_line((char *)p-dlc_header, 1),
			"Algorithm = 0x%x: %s", alg, alg_string);
	p += sizeof (alg);
	this_ext_len -= sizeof (alg);

	/* AAA SPI */
	GETSPI(p, spi_hi, spi_low);
	(void) sprintf(get_line((char *)p - dlc_header, 1),
			"AAA Security Parameter Index = 0x%x%x",
			ntohs(spi_hi), ntohs(spi_low));
	p += sizeof (spi_hi) + sizeof (spi_low);
	this_ext_len -= sizeof (spi_hi) + sizeof (spi_low);

	/* HA / FA SPI */
	GETSPI(p, spi_hi, spi_low);
	(void) sprintf(get_line((char *)p - dlc_header, 1),
			"%s Security Parameter Index = 0x%x%x",
			hafa, ntohs(spi_hi), ntohs(spi_low));
	p += sizeof (spi_hi) + sizeof (spi_low);
	this_ext_len -= sizeof (spi_hi) + sizeof (spi_low);

	/* The rest is the security info; dump it in hex */
	sprintf(sec_msg, "%s Security Info = %%s", hafa);
	dumphex(p,
		/* don't write past our string buffer ... */
		(this_ext_len*3 > BUFLEN ? BUFLEN : this_ext_len),
		auth_prn_str,
		sec_msg);
}

/*ARGSUSED*/
static void trav_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
	struct in_addr addr_temp;

	/* skip reserved */
	p += 2;
	this_ext_len -= 2;

	/* Mobile-Home Traversal Address */
	(void) memcpy(&(addr_temp.s_addr), p, sizeof (addr_temp.s_addr));
	(void) sprintf(get_line((char *)p-dlc_header, 1),
			"Mobile-Home Traversal Address= %s, %s",
			inet_ntoa(addr_temp),
			addrtoname(AF_INET, &addr_temp));
	p += sizeof (addr_temp.s_addr);
	this_ext_len -= sizeof (addr_temp.s_addr);

	/* Home-Mobile Traversal Address */
	(void) memcpy(&(addr_temp.s_addr), p, sizeof (addr_temp.s_addr));
	(void) sprintf(get_line((char *)p-dlc_header, 1),
			"Home-Mobile Traversal Address= %s, %s",
			inet_ntoa(addr_temp),
			addrtoname(AF_INET, &addr_temp));
}

/*ARGSUSED*/
static void empty_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
	/* no payload */
}

/*ARGSUSED*/
static void nai_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
	/* payload points to the NAI */
	char *desc = "Network Access Identifier = ";
	size_t desclen = strlen(desc) + 1 + this_ext_len;

	(void) snprintf(get_line((char *)p-dlc_header, 1),
			desclen > MAXLINE ? MAXLINE : desclen,
			"%s%s", desc, p);
}

/*ARGSUSED*/
static void chall_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
	char	auth_prn_str[BUFLEN];

	/* payload points to the challenge */
	dumphex(p,
		/* don't write past our string buffer ... */
		(this_ext_len*3 > BUFLEN ? BUFLEN / 3 : this_ext_len),
		auth_prn_str,
		"Challenge = %s");
}

/*ARGSUSED*/
static void ma_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
	mobagtadvext_t adv_ext[1];
	int i, len;
	struct in_addr temp_addr;

	(void) memcpy(adv_ext, p - sizeof (exthdr_t), sizeof (*adv_ext));
	(void) sprintf(get_line(0, 0), "Sequence number = %d",
			ntohs(adv_ext->sequence_num));
	(void) sprintf(get_line(0, 0),
			"Registration lifetime = %d seconds",
			ntohs(adv_ext->reg_lifetime));
	if (adv_ext->reg_bit) {
	    (void) sprintf(get_line(0, 0),
				"1... .... = registration required "
				"through FA");
	} else {
	    (void) sprintf(get_line(0, 0),
				"0... .... = registration not required "
				"through FA");
	}
	if (adv_ext->busy_bit) {
	    (void) sprintf(get_line(0, 0), ".1.. .... = FA busy");
	} else {
	    (void) sprintf(get_line(0, 0), ".0.. .... = FA not busy");
	}
	if (adv_ext->ha_bit) {
	    (void) sprintf(get_line(0, 0), "..1. .... = node is HA");
	} else {
	    (void) sprintf(get_line(0, 0), "..0. .... = node not HA");
	}
	if (adv_ext->fa_bit) {
	    (void) sprintf(get_line(0, 0), "...1 .... = node is FA ");
	} else {
	    (void) sprintf(get_line(0, 0), "...0 .... = node not FA ");
	}
	if (adv_ext->minencap_bit) {
	    (void) sprintf(get_line(0, 0), ".... 1... = minimal encapsulation "
							"supported");
	} else {
	    (void) sprintf(get_line(0, 0),
				".... 0... = no minimal encapsulation");
	}
	if (adv_ext->greencap_bit) {
	    (void) sprintf(get_line(0, 0),
				".... .1.. =  GRE encapsulation supported");
	} else {
	    (void) sprintf(get_line(0, 0),
				".... .0.. = no GRE encapsulation");
	}
	if (adv_ext->vanjacob_hdr_comp_bit) {
	    (void) sprintf(get_line(0, 0),
				".... ..1. = VJ header compression");
	} else {
	    (void) sprintf(get_line(0, 0),
				".... ..0. = no VJ header compression");
	}
	if (adv_ext->reverse_tunnel_bit) {
	    (void) sprintf(get_line(0, 0),
				".... ...1 = reverse tunneling supported");
	} else {
	    (void) sprintf(get_line(0, 0),
				".... ...0 = no reverse tunneling");
	}
	(void) sprintf(get_line(0, 0),
			"Reserved Byte = 0x%x", adv_ext->reserved);

	/* Parse out COA's */
	p += sizeof (*adv_ext);
	len = this_ext_len + sizeof (exthdr_t);
	/* this_ext_len is unsigned, and here we need a signed number */
	len -= sizeof (*adv_ext);

	for (i = 0; len >= sizeof (temp_addr.s_addr); i++) {
	    memcpy(&(temp_addr.s_addr), p - sizeof (exthdr_t),
		sizeof (temp_addr.s_addr));

	    (void) sprintf(get_line(0, 0),
				"Care of address-%d = %s, %s", i,
				inet_ntoa(temp_addr),
				addrtoname(AF_INET, &temp_addr));

	    p += sizeof (temp_addr);
	    len -= sizeof (temp_addr);
	}
}

/*ARGSUSED*/
static void prefix_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
	int i;

	for (i = 0; i < this_ext_len; i++) {
	    (void) sprintf(get_line(0, 0),
				"Prefix length of router address[%d] "
				"= %d bits",
				i, p[i]);
	}
}

/*ARGSUSED*/
static void unk_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
	char	auth_prn_str[BUFLEN];

	/* Unknown extension; just dump the rest of the payload */
	dumphex(p,
		/* don't write past our string buffer ... */
		(this_ext_len*3 > BUFLEN ? BUFLEN : this_ext_len),
		auth_prn_str,
		"Payload = %s");
}