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
46extern char *dlc_header;
47extern char *addrtoname();
48
49enum 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 */
62typedef void interpreter_f(uint8_t type, uint8_t len, uchar_t *payload);
63
64struct ext_dispatch {
65	uint8_t type;
66	interpreter_f *pfunc;
67};
68
69/* Description structure -- maps type to description */
70struct 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 */
79static void spi_ext(uint8_t, uint8_t, uchar_t *);
80static void key_ext(uint8_t, uint8_t, uchar_t *);
81static void trav_ext(uint8_t, uint8_t, uchar_t *);
82static void empty_ext(uint8_t, uint8_t, uchar_t *);
83static void nai_ext(uint8_t, uint8_t, uchar_t *);
84static void chall_ext(uint8_t, uint8_t, uchar_t *);
85static void ma_ext(uint8_t, uint8_t, uchar_t *);
86static void prefix_ext(uint8_t, uint8_t, uchar_t *);
87static 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 */
94static 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) */
111static 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 */
117static 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 */
136static 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 */
146static 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
159static 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
169static 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 */
183const char *get_mip_adv_desc(uint8_t type) {
184	return (get_desc(adv_desc, type, ADV_TBL_LEN));
185}
186
187static 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
198static int
199interpret_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
279void 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
287void
288interpret_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*/
633static 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
653static 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*/
708static 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*/
733static void empty_ext(uint8_t type, uint8_t this_ext_len, uchar_t *p) {
734	/* no payload */
735}
736
737/*ARGSUSED*/
738static 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*/
749static 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*/
761static 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*/
848static 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*/
860static 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