Home | History | Annotate | Download | only in snoop
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include <stdio.h>
     30 #include <fcntl.h>
     31 #include <sys/socket.h>
     32 #include <netinet/in.h>
     33 #include <protocols/routed.h>
     34 #include <string.h>
     35 #include <arpa/inet.h>
     36 #include "snoop.h"
     37 #include "snoop_mip.h"
     38 
     39 /*
     40  * This defines the length of internal, unbounded buffers. We set
     41  * this to be MAXLINE (the maximum verbose display line length) -
     42  * 64, which should be enough for all necessary descriptions.
     43  */
     44 #define	BUFLEN	MAXLINE - 64
     45 
     46 extern char *dlc_header;
     47 extern char *addrtoname();
     48 
     49 enum EXT_TYPE { ADV, REG };
     50 
     51 /*
     52  * This defines the interface for all extention interpreter
     53  * functions. The function will be called with following
     54  * parameters:
     55  *
     56  * type:	IN	The type code for this extention
     57  * len		IN	The length of the payload (i.e. the
     58  *			length field in an extension header)
     59  * payload	IN	A pointer to the beginning of the
     60  *			extension payload
     61  */
     62 typedef void interpreter_f(uint8_t type, uint8_t len, uchar_t *payload);
     63 
     64 struct ext_dispatch {
     65 	uint8_t type;
     66 	interpreter_f *pfunc;
     67 };
     68 
     69 /* Description structure -- maps type to description */
     70 struct ext_desc {
     71 	uint8_t type;
     72 	const char *desc;
     73 };
     74 
     75 /*
     76  * Interpreter function prototypes for both adv and reg. These
     77  * all must implement the interpret_f interface defined above.
     78  */
     79 static void spi_ext(uint8_t, uint8_t, uchar_t *);
     80 static void key_ext(uint8_t, uint8_t, uchar_t *);
     81 static void trav_ext(uint8_t, uint8_t, uchar_t *);
     82 static void empty_ext(uint8_t, uint8_t, uchar_t *);
     83 static void nai_ext(uint8_t, uint8_t, uchar_t *);
     84 static void chall_ext(uint8_t, uint8_t, uchar_t *);
     85 static void ma_ext(uint8_t, uint8_t, uchar_t *);
     86 static void prefix_ext(uint8_t, uint8_t, uchar_t *);
     87 static void unk_ext(uint8_t, uint8_t, uchar_t *);
     88 
     89 /* R E G I S T R A T I O N */
     90 
     91 #define	REG_TBL_LEN	10	/* update this when adding to the table */
     92 
     93 /* Reg: type to description mapping table */
     94 static struct ext_desc reg_desc[] = {
     95 	MN_HA_AUTH,	"(Mobile-Home Authentication Extension)",
     96 	MN_FA_AUTH,	"(Mobile-Foreign Authentication Extension",
     97 	FA_HA_AUTH,	"(Foreign-Home Authentication Extension)",
     98 	GEN_AUTH,	"(Generalized Authentication Extension)",
     99 	MN_HA_KEY,	"(Mobile-Home Key Extension)",
    100 	MN_FA_KEY,	"(Mobile-Foreign Key Extension)",
    101 	MN_HA_TRAVERSE,	"(Firewall Traversal Extension)",
    102 	ENCAP_DELIV,	"(Encapsulating Delivery Style Extension)",
    103 	MN_NAI,		"(Mobile Node Network Access Identifier)",
    104 	FA_CHALLENGE,	"(Mobile-Foreign Agent Challenge)",
    105 	0,		"(Unrecognized Extension)"
    106 };
    107 
    108 #define	GENAUTH_TBL_LEN	1	/* update this when adding to the table */
    109 
    110 /* Subtypes for Generic Authentication Extension type (type 36) */
    111 static struct ext_desc genauth_desc[] = {
    112 	GEN_AUTH_MN_AAA,	"(MN-AAA Authentication Subtype)",
    113 	0,			"(Unrecognized Subtype)"
    114 };
    115 
    116 /* Reg: type to function mapping table */
    117 static struct ext_dispatch reg_dispatch[] = {
    118 	MN_HA_AUTH,	spi_ext,
    119 	MN_FA_AUTH,	spi_ext,
    120 	FA_HA_AUTH,	spi_ext,
    121 	GEN_AUTH,	spi_ext,
    122 	MN_HA_KEY,	key_ext,
    123 	MN_FA_KEY,	key_ext,
    124 	MN_HA_TRAVERSE,	trav_ext,
    125 	ENCAP_DELIV,	empty_ext,
    126 	MN_NAI,		nai_ext,
    127 	FA_CHALLENGE,	chall_ext,
    128 	0,		unk_ext
    129 };
    130 
    131 /* A D V E R T I S E M E N T */
    132 
    133 #define	ADV_TBL_LEN	5	/* update this when adding to the table */
    134 
    135 /* Adv: type to description mapping table */
    136 static struct ext_desc adv_desc[] = {
    137 	ICMP_ADV_MSG_PADDING_EXT,	"(Padding)",
    138 	ICMP_ADV_MSG_MOBILITY_AGT_EXT,	"(Mobility Agent Extension)",
    139 	ICMP_ADV_MSG_PREFIX_LENGTH_EXT,	"(Prefix Lengths)",
    140 	ICMP_ADV_MSG_FA_CHALLENGE,	"(Foreign Agent Challenge)",
    141 	ICMP_ADV_MSG_FA_NAI,		"(Foreign Agent NAI)",
    142 	0,				"(Unrecognized Extension)"
    143 };
    144 
    145 /* Adv: type to function mapping table */
    146 static struct ext_dispatch adv_dispatch[] = {
    147 	ICMP_ADV_MSG_PADDING_EXT,	NULL,	/* never called */
    148 	ICMP_ADV_MSG_MOBILITY_AGT_EXT,	ma_ext,
    149 	ICMP_ADV_MSG_PREFIX_LENGTH_EXT,	prefix_ext,
    150 	ICMP_ADV_MSG_FA_CHALLENGE,	chall_ext,
    151 	ICMP_ADV_MSG_FA_NAI,		nai_ext,
    152 	0,				unk_ext
    153 };
    154 
    155 #define	GETSPI(payload, hi, low) \
    156 	(void) memcpy(&hi, payload, sizeof (hi)); \
    157 	(void) memcpy(&low, payload + sizeof (hi), sizeof (low))
    158 
    159 static void dumphex(uchar_t *payload, int payload_len, char *buf, char *msg) {
    160 	int index;
    161 
    162 	for (index = 0; index < payload_len; index++) {
    163 		(void) sprintf(&buf[index * 3], " %.2x", payload[index]);
    164 	}
    165 
    166 	(void) sprintf(get_line((char *)payload-dlc_header, 1), msg, buf);
    167 }
    168 
    169 static const char *get_desc(struct ext_desc table[], uint8_t type, int max) {
    170 	int i;
    171 
    172 	for (i = 0; i < max && table[i].type != type; i++)
    173 	    /* NO_OP */;
    174 
    175 	return (table[i].desc);
    176 }
    177 
    178 /*
    179  * The following is an accessor for the description table, used by
    180  * snoop_icmp.c. This maintains the encapsulation of the internal
    181  * description table.
    182  */
    183 const char *get_mip_adv_desc(uint8_t type) {
    184 	return (get_desc(adv_desc, type, ADV_TBL_LEN));
    185 }
    186 
    187 static interpreter_f *get_interpreter(struct ext_dispatch table[],
    188 				uint8_t type,
    189 				int max) {
    190 	int i;
    191 
    192 	for (i = 0; i < max && table[i].type != type; i++)
    193 	    /* NO_OP */;
    194 
    195 	return (table[i].pfunc);
    196 }
    197 
    198 static int
    199 interpret_extensions(uchar_t *ext,
    200 			int regext_size,
    201 			enum EXT_TYPE etype) {
    202 
    203 	int curr_size  =  regext_size; /* remaining total for all exts */
    204 	exthdr_t *exthdr;
    205 	gen_exthdr_t *gen_exthdr;
    206 	const char *st;
    207 	uchar_t	*p;
    208 	interpreter_f *f;
    209 	uint8_t	ext_type;
    210 	uint16_t ext_len;
    211 	uint_t ext_hdrlen;
    212 
    213 	show_space();
    214 	exthdr = (exthdr_t *)ALIGN(ext);
    215 
    216 
    217 	do {
    218 	    ext_type = exthdr->type;
    219 	    if (ext_type == GEN_AUTH) {
    220 		gen_exthdr = (gen_exthdr_t *)exthdr;
    221 		ext_hdrlen = sizeof (gen_exthdr_t);
    222 		ext_len = ntohs(gen_exthdr->length);
    223 	    } else {
    224 		ext_hdrlen = sizeof (exthdr_t);
    225 		ext_len = exthdr->length;
    226 	    }
    227 
    228 	    if (!((etype == ADV && ext_type == ICMP_ADV_MSG_PADDING_EXT &&
    229 		curr_size >= 1) ||
    230 		curr_size >= ext_hdrlen + ext_len))
    231 		    break;
    232 
    233 	    /* Print description for this extension */
    234 	    if (etype == ADV) {
    235 		st = get_desc(adv_desc, ext_type, ADV_TBL_LEN);
    236 	    } else /* REG */ {
    237 		st = get_desc(reg_desc, ext_type, REG_TBL_LEN);
    238 	    }
    239 
    240 	    (void) sprintf(get_line((char *)exthdr-dlc_header, 1),
    241 			"Extension header type = %d  %s", ext_type, st);
    242 
    243 	    if (ext_type == GEN_AUTH) {
    244 		st = get_desc(genauth_desc, gen_exthdr->subtype,
    245 		    GENAUTH_TBL_LEN);
    246 		(void) sprintf(get_line((char *)exthdr-dlc_header, 1),
    247 		    "Subtype = %d %s", gen_exthdr->subtype, st);
    248 	    }
    249 
    250 	    /* Special case for 1-byte padding */
    251 	    if (etype == ADV && ext_type == ICMP_ADV_MSG_PADDING_EXT) {
    252 		exthdr = (exthdr_t *)((uchar_t *)exthdr + 1);
    253 		curr_size--;
    254 		continue;
    255 	    }
    256 
    257 	    (void) sprintf(get_line((char *)&exthdr->length-dlc_header, 1),
    258 			"Length = %d", ext_len);
    259 
    260 	    /* Parse out the extension's payload */
    261 	    p = (uchar_t *)exthdr + ext_hdrlen;
    262 	    curr_size -= (ext_hdrlen + ext_len);
    263 
    264 	    if (etype == ADV) {
    265 		f = get_interpreter(adv_dispatch, ext_type, ADV_TBL_LEN);
    266 	    } else /* REG */ {
    267 		f = get_interpreter(reg_dispatch, ext_type, REG_TBL_LEN);
    268 	    }
    269 
    270 	    f(ext_type, ext_len, p);
    271 
    272 	    show_space();
    273 	    exthdr = (exthdr_t *)(p + ext_len);
    274 	} while (B_TRUE);
    275 
    276 	return (0);
    277 }
    278 
    279 void interpret_icmp_mip_ext(uchar_t *p, int len) {
    280 	show_space();
    281 	show_header("ICMP:  ", " MIP Advertisement Extensions ", len);
    282 	show_space();
    283 
    284 	interpret_extensions(p, len, ADV);
    285 }
    286 
    287 void
    288 interpret_mip_cntrlmsg(int flags, uchar_t *msg, int fraglen) {
    289 	char		*pt, *pc = NULL;
    290 	char		*line;
    291 	regreq_t	rreq[1];
    292 	regrep_t	rrep[1];
    293 	int		regext_size;
    294 	uchar_t		*regext_data;
    295 	struct in_addr	addr_temp;
    296 
    297 
    298 	/* First byte of the message should be the type */
    299 	switch (*msg) {
    300 	case REG_TYPE_REQ:
    301 		if (fraglen < sizeof (regreq_t))
    302 			return;
    303 		pt = (flags & F_DTAIL ? "registration request ":"reg rqst ");
    304 
    305 		(void) memcpy(rreq, msg, sizeof (*rreq));
    306 		regext_size = fraglen - sizeof (regreq_t);
    307 		regext_data = msg + sizeof (*rreq);
    308 		break;
    309 	case REG_TYPE_REP:
    310 		if (fraglen < sizeof (regrep_t))
    311 			return;
    312 		pt = (flags & F_DTAIL ? "registration reply ":"reg reply ");
    313 
    314 		(void) memcpy(rrep, msg, sizeof (*rrep));
    315 		regext_size = fraglen - sizeof (regrep_t);
    316 		regext_data = msg + sizeof (*rrep);
    317 
    318 		switch (rrep->code) {
    319 		case  REPLY_CODE_ACK:
    320 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL)) ?
    321 			    "OK" : "OK code 0";
    322 			break;
    323 		case  REPLY_CODE_ACK_NO_SIMULTANEOUS:
    324 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    325 			    "OK simultaneous bindings" : "OK code 1";
    326 			break;
    327 		case  REPLY_CODE_FA_NACK_UNSPECIFIED:
    328 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    329 			    "FA denial: unspecified":"FA denial: code 64";
    330 			break;
    331 		case  REPLY_CODE_FA_NACK_PROHIBITED:
    332 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    333 			    "FA denial: prohibited":"FA denial: code 65";
    334 			break;
    335 		case  REPLY_CODE_FA_NACK_RESOURCES:
    336 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    337 			    "FA denial: no resources":"FA denial: code 66";
    338 			break;
    339 		case  REPLY_CODE_FA_NACK_MN_AUTH:
    340 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    341 			    "FA denial: MN auth failed":"FA denial: code 67";
    342 			break;
    343 		case  REPLY_CODE_FA_NACK_HA_AUTH:
    344 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    345 			    "FA denial: HA auth failed":
    346 			    "FA denial: code 68";
    347 			break;
    348 		case  REPLY_CODE_FA_NACK_LIFETIME:
    349 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    350 			    "FA denial: lifetime":"FA denial: code 69";
    351 			break;
    352 		case  REPLY_CODE_FA_NACK_BAD_REQUEST:
    353 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    354 			    "FA denial: bad request": "FA: code 70";
    355 			break;
    356 		case  REPLY_CODE_FA_NACK_BAD_REPLY:
    357 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    358 			    "FA denial: bad Reply":"FA denial: code 71";
    359 			break;
    360 		case  REPLY_CODE_FA_NACK_ENCAP_UNAVAILABLE:
    361 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    362 			    "FA denial: encapsulation":"FA denial: code 72";
    363 			break;
    364 		case  REPLY_CODE_FA_NACK_VJ_UNAVAILABLE:
    365 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    366 			    "FA denial: VJ compression":"FA denial: code 73";
    367 			break;
    368 		case  REPLY_CODE_FA_NACK_BIDIR_TUNNEL_UNAVAILABLE:
    369 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    370 			    "FA denial: reverse tunnel unavailable":
    371 				"FA denial: code 74";
    372 			break;
    373 		case  REPLY_CODE_FA_NACK_BIDIR_TUNNEL_NO_TBIT:
    374 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    375 			    "FA denial: reverse tunnel: missing T-bit":
    376 				"FA denial: code 75";
    377 			break;
    378 		case  REPLY_CODE_FA_NACK_BIDIR_TUNNEL_TOO_DISTANT:
    379 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    380 			    "FA denial: reverse tunnel: too distant":
    381 				"FA denial: code 76";
    382 			break;
    383 		case  REPLY_CODE_FA_NACK_ICMP_HA_NET_UNREACHABLE:
    384 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    385 			    "FA denial: home network unreachable":
    386 			    "FA denial: code 80";
    387 			break;
    388 		case  REPLY_CODE_FA_NACK_ICMP_HA_HOST_UNREACHABLE:
    389 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    390 			    "FA denial: HA host unreachable":
    391 			    "FA denial: code 81";
    392 			break;
    393 		case  REPLY_CODE_FA_NACK_ICMP_HA_PORT_UNREACHABLE:
    394 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    395 			    "FA denial: HA port unreachable":
    396 			    "FA denial: code 82";
    397 			break;
    398 		case  REPLY_CODE_FA_NACK_ICMP_HA_UNREACHABLE:
    399 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    400 			    "FA denial: HA unreachable":"FA denial: code 88";
    401 			break;
    402 		case REPLY_CODE_FA_NACK_UNIQUE_HOMEADDR_REQD:
    403 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    404 			    "FA denial: Unique Home Addr Required":
    405 				"FA denial: code 96";
    406 			break;
    407 		case REPLY_CODE_FA_NACK_MISSING_NAI:
    408 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    409 			    "FA denial: Missing NAI":
    410 				"FA denial: code 97";
    411 			break;
    412 		case REPLY_CODE_FA_NACK_MISSING_HOME_AGENT:
    413 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    414 			    "FA denial: Missing Home Agent":
    415 				"FA denial: code 98";
    416 			break;
    417 		case REPLY_CODE_FA_NACK_UNKNOWN_CHALLENGE:
    418 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    419 			    "FA denial: Unknown Challenge":
    420 				"FA denial: code 104";
    421 			break;
    422 		case REPLY_CODE_FA_NACK_MISSING_CHALLENGE:
    423 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    424 			    "FA denial: Missing Challenge":
    425 				"FA denial: code 105";
    426 			break;
    427 		case REPLY_CODE_FA_NACK_MISSING_MN_FA:
    428 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    429 			    "FA denial: Missing Mobile-Foreign Key Extension":
    430 				"FA denial: code 106";
    431 			break;
    432 		case  REPLY_CODE_HA_NACK_UNSPECIFIED:
    433 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    434 			    "HA denial: unspecified":"HA denial: code 128";
    435 			break;
    436 		case  REPLY_CODE_HA_NACK_PROHIBITED:
    437 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    438 			    "HA denial: prohibited":"HA denial: code 129";
    439 			break;
    440 		case  REPLY_CODE_HA_NACK_RESOURCES:
    441 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    442 			    "HA denial: no resources":"HA denial: code 130";
    443 			break;
    444 		case  REPLY_CODE_HA_NACK_MN_AUTH:
    445 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    446 			    "HA denial: MN auth failed":"HA denial: code 131";
    447 			break;
    448 		case  REPLY_CODE_HA_NACK_FA_AUTH:
    449 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    450 			    "HA denial: FA auth failed":"HA denial: code 132";
    451 			break;
    452 		case  REPLY_CODE_HA_NACK_ID_MISMATCH:
    453 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    454 			    "HA denial: ID mismatch":"HA denial: code 133";
    455 			break;
    456 		case  REPLY_CODE_HA_NACK_BAD_REQUEST:
    457 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    458 			    "HA denial: bad request":"HA denial: code 134";
    459 			break;
    460 		case  REPLY_CODE_HA_NACK_TOO_MANY_BINDINGS:
    461 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    462 			    "HA denial: too many bindings":
    463 			    "HA denial: code 135";
    464 			break;
    465 		case  REPLY_CODE_HA_NACK_BAD_HA_ADDRESS:
    466 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    467 			    "HA denial: bad HA address":"HA denial: code 136";
    468 			break;
    469 		case  REPLY_CODE_HA_NACK_BIDIR_TUNNEL_UNAVAILABLE:
    470 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    471 			    "HA denial: no reverse tunnel":
    472 			    "HA denial: code 137";
    473 			break;
    474 		case  REPLY_CODE_HA_NACK_BIDIR_TUNNEL_NO_TBIT:
    475 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    476 			    "HA denial: reverse tunnel: no T-bit":
    477 			    "HA denial: code 138";
    478 			break;
    479 		case  REPLY_CODE_HA_NACK_BIDIR_ENCAP_UNAVAILABLE:
    480 			pc = ((flags & F_ALLSUM) || (flags & F_DTAIL))?
    481 			    "HA denial: encapsulation unavailable":
    482 			    "HA denial: code 139";
    483 			break;
    484 		default:
    485 			pc = "?";
    486 			break;
    487 		}
    488 		break;
    489 
    490 	default :
    491 		break;
    492 	}
    493 	if (flags & F_SUM) {
    494 		line = get_sum_line();
    495 
    496 		if (pc != NULL)
    497 			(void) sprintf(line, "Mobile IP %s(%s)", pt, pc);
    498 		else
    499 			(void) sprintf(line, "Mobile IP %s", pt);
    500 	}
    501 
    502 	if (flags & F_DTAIL) {
    503 		show_header("MIP:  ", "Mobile IP Header", fraglen);
    504 		show_space();
    505 
    506 		if (*msg == REG_TYPE_REQ) {
    507 			(void) sprintf(get_line((char *)&rreq -
    508 			    dlc_header, 1), "Registration header type = %s",
    509 			    pt);
    510 			(void) sprintf(get_line(
    511 			    (char *)(((uchar_t *)&rreq) + 1) - dlc_header, 1),
    512 			    "%d... .... = %s simultaneous bindings  ",
    513 			    (rreq->Simultaneous_registration == 1)? 1 : 0,
    514 			    (rreq->Simultaneous_registration == 1)? "":"no");
    515 			(void) sprintf(get_line(
    516 			    (char *)(((uchar_t *)&rreq) + 1) - dlc_header, 1),
    517 			    ".%d.. .... = %s broadcast datagrams ",
    518 			    (rreq->Broadcasts_desired == 1) ?  1 : 0,
    519 			    (rreq->Broadcasts_desired == 1) ? "":"no");
    520 			(void) sprintf(get_line(
    521 			    (char *)(((uchar_t *)&rreq) + 1) - dlc_header, 1),
    522 			    "..%d. .... = %s decapsulation by MN",
    523 			    (rreq->Decapsulation_done_locally == 1) ? 1 : 0,
    524 			    (rreq->Decapsulation_done_locally == 1) ?
    525 				"" : "no");
    526 			(void) sprintf(get_line(
    527 			    (char *)(((uchar_t *)&rreq) + 1) - dlc_header, 1),
    528 			    "...%d .... = %s minimum encapsulation ",
    529 			    (rreq->Minimal_encap_desired == 1) ? 1 : 0,
    530 			    (rreq->Minimal_encap_desired == 1) ? "" : "no");
    531 			(void) sprintf(get_line(
    532 			    (char *)(((uchar_t *)&rreq) + 1) - dlc_header, 1),
    533 			    ".... %d... = %s GRE encapsulation ",
    534 			    (rreq->GRE_encap_desired == 1) ? 1 : 0,
    535 			    (rreq->GRE_encap_desired == 1) ? "" : "no");
    536 			(void) sprintf(get_line(
    537 			    (char *)(((uchar_t *)&rreq) + 1) - dlc_header, 1),
    538 			    ".... .%d.. = %s VJ hdr Compression ",
    539 			    (rreq->VJ_compression_desired == 1) ? 1 : 0,
    540 			    (rreq->VJ_compression_desired == 1) ? "" : "no");
    541 			(void) sprintf(get_line(
    542 			    (char *)(((uchar_t *)&rreq) + 1) - dlc_header, 1),
    543 			    ".... ..%d. = %s reverse tunnel",
    544 			    (rreq->BiDirectional_Tunnel_desired == 1) ? 1 : 0,
    545 			    (rreq->BiDirectional_Tunnel_desired == 1) ?
    546 				"" : "no");
    547 			if (ntohs(rreq->lifetime) == 0xffff) {
    548 				(void) sprintf(get_line(
    549 				    (char *)&rreq->lifetime - dlc_header, 1),
    550 				    "Life Time = 0xFFFF (infinity)");
    551 			} else if (ntohs(rreq->lifetime) == 0) {
    552 				(void) sprintf(get_line(
    553 				    (char *)&rreq->lifetime - dlc_header, 1),
    554 				    "Life Time = 0 "
    555 				    "(request for de-registration)");
    556 			} else {
    557 				(void) sprintf(get_line(
    558 				    (char *)&rreq->lifetime - dlc_header, 1),
    559 				    "Life time = %d seconds",
    560 				    ntohs(rreq->lifetime));
    561 			}
    562 			addr_temp.s_addr = rreq->home_addr;
    563 			(void) sprintf(get_line(
    564 			    (char *)&rreq->home_addr - dlc_header, 1),
    565 			    "Home address = %s, %s",
    566 			    inet_ntoa(addr_temp),
    567 			    addrtoname(AF_INET, &addr_temp));
    568 			addr_temp.s_addr = rreq->home_agent_addr;
    569 			(void) sprintf(get_line(
    570 			    (char *)&rreq->home_agent_addr - dlc_header, 1),
    571 			    "Home Agent address = %s, %s",
    572 			    inet_ntoa(addr_temp),
    573 			    addrtoname(AF_INET, &addr_temp));
    574 			addr_temp.s_addr = rreq->care_of_addr;
    575 			(void) sprintf(get_line(
    576 			    (char *)&rreq->care_of_addr - dlc_header, 1),
    577 			    "Care of address = %s, %s",
    578 			    inet_ntoa(addr_temp),
    579 			    addrtoname(AF_INET, &addr_temp));
    580 			(void) sprintf(get_line(
    581 			    (char *)&rreq->identification - dlc_header, 1),
    582 			    "Identification = 0x%x-%x",
    583 			    ntohl(rreq->identification.high_bits),
    584 			    ntohl(rreq->identification.low_bits));
    585 		} else if (*msg == REG_TYPE_REP) {
    586 			(void) sprintf(
    587 			    get_line((char *)&rrep->type - dlc_header, 1),
    588 			    "Registration header type = %d (%s)",
    589 			    (int)rrep->type, pt);
    590 			(void) sprintf(get_line((char *)&rrep - dlc_header, 1),
    591 			    "Code = %d %s", (int)rrep->code, pc);
    592 			if (ntohs(rrep->lifetime) == 0xffff) {
    593 				(void) sprintf(get_line(
    594 				    (char *)&rrep->lifetime - dlc_header, 1),
    595 				    "Life time = 0xFFFF (infinity)");
    596 			} else if (ntohs(rrep->lifetime) == 0) {
    597 				(void) sprintf(get_line(
    598 				    (char *)&rrep->lifetime - dlc_header, 1),
    599 				    ((rrep->code == REPLY_CODE_ACK) ||
    600 				    (rrep->code ==
    601 					REPLY_CODE_ACK_NO_SIMULTANEOUS))?
    602 				    "Life time = 0 (de-registeration success)" :
    603 				    "Life time = 0 (de-registration failed)");
    604 			} else {
    605 				(void) sprintf(get_line(
    606 				    (char *)&rrep->lifetime - dlc_header, 1),
    607 				    "Life time = %d seconds",
    608 				    ntohs(rrep->lifetime));
    609 			}
    610 			addr_temp.s_addr = rrep->home_addr;
    611 			(void) sprintf(
    612 			    get_line((char *)&rrep->home_addr - dlc_header, 1),
    613 			    "Home address = %s, %s",
    614 			    inet_ntoa(addr_temp),
    615 			    addrtoname(AF_INET, &addr_temp));
    616 			addr_temp.s_addr = rrep->home_agent_addr;
    617 			(void) sprintf(get_line(
    618 			    (char *)&rrep->home_agent_addr - dlc_header, 1),
    619 			    "Home Agent address = %s, %s",
    620 			    inet_ntoa(addr_temp),
    621 			    addrtoname(AF_INET, &addr_temp));
    622 			(void) sprintf(get_line(
    623 			    (char *)&rrep->identification - dlc_header, 1),
    624 			    "Identification = 0x%x-%x",
    625 			    ntohl(rrep->identification.high_bits),
    626 			    ntohl(rrep->identification.low_bits));
    627 		}
    628 		fraglen = interpret_extensions(regext_data, regext_size, REG);
    629 	}
    630 }
    631 
    632 /*ARGSUSED*/
    633 static void spi_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
    634 	uint16_t spi_hi, spi_low;
    635 	char	auth_prn_str[BUFLEN];
    636 
    637 	/* SPI */
    638 	GETSPI(p, spi_hi, spi_low);
    639 	(void) sprintf(get_line((char *)p - dlc_header, 1),
    640 			"Security Parameter Index = 0x%x%x",
    641 			ntohs(spi_hi), ntohs(spi_low));
    642 	p += sizeof (spi_hi) + sizeof (spi_low);
    643 	this_ext_len -= sizeof (spi_hi) + sizeof (spi_low);
    644 
    645 	/* The rest is the authenticator; dump it in hex */
    646 	dumphex(p,
    647 		/* don't write past our string buffer ... */
    648 		(this_ext_len*3 > BUFLEN ? BUFLEN : this_ext_len),
    649 		auth_prn_str,
    650 		"Authenticator = %s");
    651 }
    652 
    653 static void key_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
    654 	uint16_t alg, spi_hi, spi_low;
    655 	char *alg_string;
    656 	char *hafa = (type == MN_HA_KEY ? "HA" : "FA");
    657 	char sec_msg[32];
    658 	char auth_prn_str[BUFLEN];
    659 
    660 	/* Algorithm Type */
    661 	(void) memcpy(&alg, p, sizeof (alg));
    662 	alg = ntohs(alg);
    663 	switch (alg) {
    664 	case KEY_ALG_NONE:
    665 	    alg_string = "None";
    666 	    break;
    667 	case SA_MD5_MODE_PREF_SUF:
    668 	    alg_string = "MD5/prefix+suffix";
    669 	    break;
    670 	case SA_HMAC_MD5:
    671 	    alg_string = "HMAC MD5";
    672 	    break;
    673 	default:
    674 	    alg_string = "Unknown";
    675 	    break;
    676 	}
    677 	(void) sprintf(get_line((char *)p-dlc_header, 1),
    678 			"Algorithm = 0x%x: %s", alg, alg_string);
    679 	p += sizeof (alg);
    680 	this_ext_len -= sizeof (alg);
    681 
    682 	/* AAA SPI */
    683 	GETSPI(p, spi_hi, spi_low);
    684 	(void) sprintf(get_line((char *)p - dlc_header, 1),
    685 			"AAA Security Parameter Index = 0x%x%x",
    686 			ntohs(spi_hi), ntohs(spi_low));
    687 	p += sizeof (spi_hi) + sizeof (spi_low);
    688 	this_ext_len -= sizeof (spi_hi) + sizeof (spi_low);
    689 
    690 	/* HA / FA SPI */
    691 	GETSPI(p, spi_hi, spi_low);
    692 	(void) sprintf(get_line((char *)p - dlc_header, 1),
    693 			"%s Security Parameter Index = 0x%x%x",
    694 			hafa, ntohs(spi_hi), ntohs(spi_low));
    695 	p += sizeof (spi_hi) + sizeof (spi_low);
    696 	this_ext_len -= sizeof (spi_hi) + sizeof (spi_low);
    697 
    698 	/* The rest is the security info; dump it in hex */
    699 	sprintf(sec_msg, "%s Security Info = %%s", hafa);
    700 	dumphex(p,
    701 		/* don't write past our string buffer ... */
    702 		(this_ext_len*3 > BUFLEN ? BUFLEN : this_ext_len),
    703 		auth_prn_str,
    704 		sec_msg);
    705 }
    706 
    707 /*ARGSUSED*/
    708 static void trav_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
    709 	struct in_addr addr_temp;
    710 
    711 	/* skip reserved */
    712 	p += 2;
    713 	this_ext_len -= 2;
    714 
    715 	/* Mobile-Home Traversal Address */
    716 	(void) memcpy(&(addr_temp.s_addr), p, sizeof (addr_temp.s_addr));
    717 	(void) sprintf(get_line((char *)p-dlc_header, 1),
    718 			"Mobile-Home Traversal Address= %s, %s",
    719 			inet_ntoa(addr_temp),
    720 			addrtoname(AF_INET, &addr_temp));
    721 	p += sizeof (addr_temp.s_addr);
    722 	this_ext_len -= sizeof (addr_temp.s_addr);
    723 
    724 	/* Home-Mobile Traversal Address */
    725 	(void) memcpy(&(addr_temp.s_addr), p, sizeof (addr_temp.s_addr));
    726 	(void) sprintf(get_line((char *)p-dlc_header, 1),
    727 			"Home-Mobile Traversal Address= %s, %s",
    728 			inet_ntoa(addr_temp),
    729 			addrtoname(AF_INET, &addr_temp));
    730 }
    731 
    732 /*ARGSUSED*/
    733 static void empty_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
    734 	/* no payload */
    735 }
    736 
    737 /*ARGSUSED*/
    738 static void nai_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
    739 	/* payload points to the NAI */
    740 	char *desc = "Network Access Identifier = ";
    741 	size_t desclen = strlen(desc) + 1 + this_ext_len;
    742 
    743 	(void) snprintf(get_line((char *)p-dlc_header, 1),
    744 			desclen > MAXLINE ? MAXLINE : desclen,
    745 			"%s%s", desc, p);
    746 }
    747 
    748 /*ARGSUSED*/
    749 static void chall_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
    750 	char	auth_prn_str[BUFLEN];
    751 
    752 	/* payload points to the challenge */
    753 	dumphex(p,
    754 		/* don't write past our string buffer ... */
    755 		(this_ext_len*3 > BUFLEN ? BUFLEN / 3 : this_ext_len),
    756 		auth_prn_str,
    757 		"Challenge = %s");
    758 }
    759 
    760 /*ARGSUSED*/
    761 static void ma_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
    762 	mobagtadvext_t adv_ext[1];
    763 	int i, len;
    764 	struct in_addr temp_addr;
    765 
    766 	(void) memcpy(adv_ext, p - sizeof (exthdr_t), sizeof (*adv_ext));
    767 	(void) sprintf(get_line(0, 0), "Sequence number = %d",
    768 			ntohs(adv_ext->sequence_num));
    769 	(void) sprintf(get_line(0, 0),
    770 			"Registration lifetime = %d seconds",
    771 			ntohs(adv_ext->reg_lifetime));
    772 	if (adv_ext->reg_bit) {
    773 	    (void) sprintf(get_line(0, 0),
    774 				"1... .... = registration required "
    775 				"through FA");
    776 	} else {
    777 	    (void) sprintf(get_line(0, 0),
    778 				"0... .... = registration not required "
    779 				"through FA");
    780 	}
    781 	if (adv_ext->busy_bit) {
    782 	    (void) sprintf(get_line(0, 0), ".1.. .... = FA busy");
    783 	} else {
    784 	    (void) sprintf(get_line(0, 0), ".0.. .... = FA not busy");
    785 	}
    786 	if (adv_ext->ha_bit) {
    787 	    (void) sprintf(get_line(0, 0), "..1. .... = node is HA");
    788 	} else {
    789 	    (void) sprintf(get_line(0, 0), "..0. .... = node not HA");
    790 	}
    791 	if (adv_ext->fa_bit) {
    792 	    (void) sprintf(get_line(0, 0), "...1 .... = node is FA ");
    793 	} else {
    794 	    (void) sprintf(get_line(0, 0), "...0 .... = node not FA ");
    795 	}
    796 	if (adv_ext->minencap_bit) {
    797 	    (void) sprintf(get_line(0, 0), ".... 1... = minimal encapsulation "
    798 							"supported");
    799 	} else {
    800 	    (void) sprintf(get_line(0, 0),
    801 				".... 0... = no minimal encapsulation");
    802 	}
    803 	if (adv_ext->greencap_bit) {
    804 	    (void) sprintf(get_line(0, 0),
    805 				".... .1.. =  GRE encapsulation supported");
    806 	} else {
    807 	    (void) sprintf(get_line(0, 0),
    808 				".... .0.. = no GRE encapsulation");
    809 	}
    810 	if (adv_ext->vanjacob_hdr_comp_bit) {
    811 	    (void) sprintf(get_line(0, 0),
    812 				".... ..1. = VJ header compression");
    813 	} else {
    814 	    (void) sprintf(get_line(0, 0),
    815 				".... ..0. = no VJ header compression");
    816 	}
    817 	if (adv_ext->reverse_tunnel_bit) {
    818 	    (void) sprintf(get_line(0, 0),
    819 				".... ...1 = reverse tunneling supported");
    820 	} else {
    821 	    (void) sprintf(get_line(0, 0),
    822 				".... ...0 = no reverse tunneling");
    823 	}
    824 	(void) sprintf(get_line(0, 0),
    825 			"Reserved Byte = 0x%x", adv_ext->reserved);
    826 
    827 	/* Parse out COA's */
    828 	p += sizeof (*adv_ext);
    829 	len = this_ext_len + sizeof (exthdr_t);
    830 	/* this_ext_len is unsigned, and here we need a signed number */
    831 	len -= sizeof (*adv_ext);
    832 
    833 	for (i = 0; len >= sizeof (temp_addr.s_addr); i++) {
    834 	    memcpy(&(temp_addr.s_addr), p - sizeof (exthdr_t),
    835 		sizeof (temp_addr.s_addr));
    836 
    837 	    (void) sprintf(get_line(0, 0),
    838 				"Care of address-%d = %s, %s", i,
    839 				inet_ntoa(temp_addr),
    840 				addrtoname(AF_INET, &temp_addr));
    841 
    842 	    p += sizeof (temp_addr);
    843 	    len -= sizeof (temp_addr);
    844 	}
    845 }
    846 
    847 /*ARGSUSED*/
    848 static void prefix_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
    849 	int i;
    850 
    851 	for (i = 0; i < this_ext_len; i++) {
    852 	    (void) sprintf(get_line(0, 0),
    853 				"Prefix length of router address[%d] "
    854 				"= %d bits",
    855 				i, p[i]);
    856 	}
    857 }
    858 
    859 /*ARGSUSED*/
    860 static void unk_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
    861 	char	auth_prn_str[BUFLEN];
    862 
    863 	/* Unknown extension; just dump the rest of the payload */
    864 	dumphex(p,
    865 		/* don't write past our string buffer ... */
    866 		(this_ext_len*3 > BUFLEN ? BUFLEN : this_ext_len),
    867 		auth_prn_str,
    868 		"Payload = %s");
    869 }
    870