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