xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_mip.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 (c) 1999 by Sun Microsystems, Inc.
24  * All rights reserved.
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 static 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