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 (c) 1991, 1999 by Sun Microsystems, Inc.
     24  * All rights reserved.
     25  */
     26 
     27 #ident	"%Z%%M%	%I%	%E% SMI"	/* SunOS	*/
     28 
     29 #include <sys/types.h>
     30 #include <sys/errno.h>
     31 #include <setjmp.h>
     32 #include <sys/tiuser.h>
     33 #include <string.h>
     34 
     35 #include <rpc/types.h>
     36 #include <rpc/xdr.h>
     37 #include <rpc/auth.h>
     38 #include <rpc/clnt.h>
     39 #include <rpc/rpc_msg.h>
     40 #include <rpc/pmap_prot.h>
     41 #include "snoop.h"
     42 
     43 /*
     44  * Number of bytes to display from a string (address, netid, etc.).
     45  */
     46 #define	MAXSTRINGLEN	64
     47 
     48 extern char *dlc_header;
     49 extern jmp_buf xdr_err;
     50 
     51 static void interpret_pmap_2(int, int, int, int, int, char *, int);
     52 static void interpret_pmap_4(int, int, int, int, int, char *, int);
     53 static void stash_callit(ulong_t, int, int, int, int);
     54 
     55 void
     56 interpret_pmap(flags, type, xid, vers, proc, data, len)
     57 	int flags, type, xid, vers, proc;
     58 	char *data;
     59 	int len;
     60 {
     61 	switch (vers) {
     62 	case 2:	interpret_pmap_2(flags, type, xid, vers, proc, data, len);
     63 		break;
     64 
     65 	/* Version 3 is a subset of version 4 */
     66 	case 3:
     67 	case 4:	interpret_pmap_4(flags, type, xid, vers, proc, data, len);
     68 		break;
     69 	}
     70 }
     71 
     72 void show_pmap();
     73 char *sum_pmaplist();
     74 void show_pmaplist();
     75 
     76 static char *procnames_short_2[] = {
     77 	"Null",		/* 0 */
     78 	"SET",		/* 1 */
     79 	"UNSET",	/* 2 */
     80 	"GETPORT",	/* 3 */
     81 	"DUMP",		/* 4 */
     82 	"CALLIT",	/* 5 */
     83 };
     84 
     85 static char *procnames_long_2[] = {
     86 	"Null procedure",	/* 0 */
     87 	"Set port",		/* 1 */
     88 	"Unset port",		/* 2 */
     89 	"Get port number",	/* 3 */
     90 	"Dump the mappings",	/* 4 */
     91 	"Indirect call",	/* 5 */
     92 };
     93 
     94 #define	MAXPROC_2	5
     95 
     96 void
     97 interpret_pmap_2(flags, type, xid, vers, proc, data, len)
     98 	int flags, type, xid, vers, proc;
     99 	char *data;
    100 	int len;
    101 {
    102 	char *line;
    103 	unsigned port, proto;
    104 	unsigned iprog, ivers, iproc, ilen;
    105 	extern int pi_frame;
    106 	struct cache_struct *x, *find_callit();
    107 	int trailer_done = 0;
    108 
    109 	if (proc < 0 || proc > MAXPROC_2)
    110 		return;
    111 
    112 	if (proc == PMAPPROC_CALLIT) {
    113 		if (type == CALL) {
    114 			iprog = getxdr_u_long();
    115 			ivers = getxdr_u_long();
    116 			iproc = getxdr_u_long();
    117 			stash_callit(xid, pi_frame,
    118 				iprog, ivers, iproc);
    119 		} else {
    120 			x = find_callit(xid);
    121 		}
    122 	}
    123 
    124 	if (flags & F_SUM) {
    125 		if (setjmp(xdr_err)) {
    126 			return;
    127 		}
    128 
    129 		line = get_sum_line();
    130 
    131 		if (type == CALL) {
    132 			(void) sprintf(line,
    133 				"PORTMAP C %s",
    134 				procnames_short_2[proc]);
    135 			line += strlen(line);
    136 			switch (proc) {
    137 			case PMAPPROC_GETPORT:
    138 				iprog = getxdr_u_long();
    139 				ivers = getxdr_u_long();
    140 				proto = getxdr_u_long();
    141 				(void) sprintf(line,
    142 					" prog=%d (%s) vers=%d proto=%s",
    143 					iprog, nameof_prog(iprog),
    144 					ivers,
    145 					getproto(proto));
    146 				break;
    147 			case PMAPPROC_CALLIT:
    148 				(void) getxdr_u_long(); /* length */
    149 				(void) sprintf(line,
    150 					" prog=%s vers=%d proc=%d",
    151 					nameof_prog(iprog),
    152 					ivers, iproc);
    153 				data += 16; /* prog+ver+proc+len */
    154 				len -= 16;
    155 				protoprint(flags, type, xid,
    156 					iprog, ivers, iproc,
    157 					data, len);
    158 				break;
    159 			default:
    160 				break;
    161 			}
    162 			check_retransmit(line, xid);
    163 		} else {
    164 			(void) sprintf(line, "PORTMAP R %s ",
    165 				procnames_short_2[proc]);
    166 			line += strlen(line);
    167 			switch (proc) {
    168 			case PMAPPROC_GETPORT:
    169 				port = getxdr_u_long();
    170 				(void) sprintf(line, "port=%d",
    171 					port);
    172 				break;
    173 			case PMAPPROC_DUMP:
    174 				(void) sprintf(line, "%s",
    175 					sum_pmaplist());
    176 				break;
    177 			case PMAPPROC_CALLIT:
    178 				port = getxdr_u_long();
    179 				ilen = getxdr_u_long();
    180 				(void) sprintf(line, "port=%d len=%d",
    181 					port, ilen);
    182 				if (x != NULL) {
    183 					protoprint(flags, type, xid,
    184 						x->xid_prog,
    185 						x->xid_vers,
    186 						x->xid_proc,
    187 						data, len);
    188 				}
    189 				break;
    190 			default:
    191 				break;
    192 			}
    193 		}
    194 	}
    195 
    196 	if (flags & F_DTAIL) {
    197 		show_header("PMAP:  ", "Portmapper", len);
    198 		show_space();
    199 		if (setjmp(xdr_err)) {
    200 			return;
    201 		}
    202 		(void) sprintf(get_line(0, 0),
    203 			"Proc = %d (%s)",
    204 			proc, procnames_long_2[proc]);
    205 		if (type == CALL) {
    206 			switch (proc) {
    207 			case PMAPPROC_NULL:
    208 			case PMAPPROC_SET:
    209 			case PMAPPROC_UNSET:
    210 				break;
    211 			case PMAPPROC_GETPORT:
    212 				iprog = getxdr_u_long();
    213 				(void) sprintf(get_line(0, 0),
    214 					"Program = %d (%s)",
    215 					iprog, nameof_prog(iprog));
    216 				(void) showxdr_u_long("Version = %d");
    217 				proto = getxdr_u_long();
    218 				(void) sprintf(get_line(0, 0),
    219 					"Protocol = %d (%s)",
    220 					proto, getproto(proto));
    221 				break;
    222 			case PMAPPROC_DUMP:
    223 				break;
    224 			case PMAPPROC_CALLIT:
    225 				(void) sprintf(get_line(0, 0),
    226 					"Program = %d (%s)",
    227 					iprog, nameof_prog(iprog));
    228 				(void) sprintf(get_line(0, 0),
    229 					"Version = %d", ivers);
    230 				(void) sprintf(get_line(0, 0),
    231 					"Proc    = %d", iproc);
    232 				(void) showxdr_u_long(
    233 					"Callit data = %d bytes");
    234 				show_trailer();
    235 				trailer_done = 1;
    236 				data += 16; /* prog+ver+proc+len */
    237 				len -= 16;
    238 				protoprint(flags, type, xid,
    239 					iprog, ivers, iproc,
    240 					data, len);
    241 				break;
    242 			}
    243 		} else {
    244 			switch (proc) {
    245 			case PMAPPROC_NULL:
    246 			case PMAPPROC_SET:
    247 			case PMAPPROC_UNSET:
    248 				break;
    249 			case PMAPPROC_GETPORT:
    250 				(void) showxdr_u_long("Port = %d");
    251 				break;
    252 			case PMAPPROC_DUMP:
    253 				show_pmaplist();
    254 				break;
    255 			case PMAPPROC_CALLIT:
    256 				(void) showxdr_u_long("Port = %d");
    257 				(void) showxdr_u_long("Length = %d bytes");
    258 				show_trailer();
    259 				trailer_done = 1;
    260 				if (x != NULL) {
    261 					protoprint(flags, type, xid,
    262 						x->xid_prog,
    263 						x->xid_vers,
    264 						x->xid_proc,
    265 						data, len);
    266 				}
    267 				break;
    268 			}
    269 		}
    270 		if (!trailer_done)
    271 			show_trailer();
    272 	}
    273 }
    274 
    275 char *
    276 sum_pmaplist()
    277 {
    278 	int maps = 0;
    279 	static char buff[16];
    280 
    281 	if (setjmp(xdr_err)) {
    282 		(void) sprintf(buff, "%d+ map(s) found", maps);
    283 		return (buff);
    284 	}
    285 
    286 	while (getxdr_u_long()) {
    287 		(void) getxdr_u_long();	/* program */
    288 		(void) getxdr_u_long();	/* version */
    289 		(void) getxdr_u_long();	/* protocol */
    290 		(void) getxdr_u_long();	/* port */
    291 		maps++;
    292 	}
    293 
    294 	(void) sprintf(buff, "%d map(s) found", maps);
    295 	return (buff);
    296 }
    297 
    298 void
    299 show_pmaplist()
    300 {
    301 	unsigned prog, vers, proto, port;
    302 	int maps = 0;
    303 
    304 	if (setjmp(xdr_err)) {
    305 		(void) sprintf(get_line(0, 0),
    306 			" %d+ maps. (Frame is incomplete)",
    307 			maps);
    308 		return;
    309 	}
    310 
    311 	(void) sprintf(get_line(0, 0),
    312 		" Program Version Protocol   Port");
    313 
    314 	while (getxdr_u_long()) {
    315 		prog  = getxdr_u_long();
    316 		vers  = getxdr_u_long();
    317 		proto = getxdr_u_long();
    318 		port  = getxdr_u_long();
    319 		(void) sprintf(get_line(0, 0),
    320 			"%8d%8d%9d%7d  %s",
    321 			prog, vers, proto, port, nameof_prog(prog));
    322 		maps++;
    323 	}
    324 
    325 	(void) sprintf(get_line(0, 0), " %d maps", maps);
    326 }
    327 
    328 /*
    329  * ******************************************
    330  */
    331 char *sum_rpcblist();
    332 void show_rpcblist();
    333 char *sum_rpcb_entry_list();
    334 void show_rpcb_entry_list();
    335 
    336 static char *procnames_short_4[] = {
    337 	/*
    338 	 * version 3 and 4 procs
    339 	 */
    340 	"Null",		/* 0 */
    341 	"SET",		/* 1 */
    342 	"UNSET",	/* 2 */
    343 	"GETADDR",	/* 3 */
    344 	"DUMP",		/* 4 */
    345 	"BCAST",	/* 5 */
    346 	"GETTIME",	/* 6 */
    347 	"UADDR2TADDR",	/* 7 */
    348 	"TADDR2UADDR",	/* 8 */
    349 	/*
    350 	 * version 4 procs only
    351 	 */
    352 	"GETVERSADDR",	/* 9 */
    353 	"INDIRECT",	/* 10 */
    354 	"GETADDRLIST",	/* 11 */
    355 	"GETSTAT",	/* 12 */
    356 };
    357 
    358 static char *procnames_long_4[] = {
    359 	/*
    360 	 * version 3 and 4 procs
    361 	 */
    362 	"Null procedure",			/* 0 */
    363 	"Set address",				/* 1 */
    364 	"Unset address",			/* 2 */
    365 	"Get address",				/* 3 */
    366 	"Dump the mappings",			/* 4 */
    367 	"Broadcast call (no error)",		/* 5 */
    368 	"Get the time",				/* 6 */
    369 	"Universal to transport address",	/* 7 */
    370 	"Transport to universal address",	/* 8 */
    371 	/*
    372 	 * version 4 procs only
    373 	 */
    374 	"Get address of specific version",	/* 9 */
    375 	"Indirect call (return error)",		/* 10 */
    376 	"Return addresses of prog/vers",	/* 11 */
    377 	"Get statistics",			/* 12 */
    378 };
    379 
    380 #define	MAXPROC_4		12
    381 #define	RPCBPROC_NULL		0
    382 
    383 void
    384 interpret_pmap_4(flags, type, xid, vers, proc, data, len)
    385 	int flags, type, xid, vers, proc;
    386 	char *data;
    387 	int len;
    388 {
    389 	char *line;
    390 	unsigned prog, ver;
    391 	char buff1[MAXSTRINGLEN + 1];
    392 	int iprog, ivers, iproc, ilen;
    393 	extern int pi_frame;
    394 	struct cache_struct *x, *find_callit();
    395 	int trailer_done = 0;
    396 
    397 	if (proc < 0 || proc > MAXPROC_4)
    398 		return;
    399 
    400 	if (proc == RPCBPROC_BCAST) {
    401 		if (type == CALL) {
    402 			iprog = getxdr_u_long();
    403 			ivers = getxdr_u_long();
    404 			iproc = getxdr_u_long();
    405 			stash_callit(xid, pi_frame,
    406 				iprog, ivers, iproc);
    407 		} else {
    408 			x = find_callit(xid);
    409 		}
    410 	}
    411 
    412 	if (flags & F_SUM) {
    413 		if (setjmp(xdr_err)) {
    414 			return;
    415 		}
    416 
    417 		line = get_sum_line();
    418 
    419 		if (type == CALL) {
    420 			(void) sprintf(line,
    421 				"RPCBIND C %s",
    422 				procnames_short_4[proc]);
    423 			line += strlen(line);
    424 			switch (proc) {
    425 			case RPCBPROC_SET:
    426 			case RPCBPROC_UNSET:
    427 			case RPCBPROC_GETADDR:
    428 			case RPCBPROC_GETVERSADDR:
    429 			case RPCBPROC_GETADDRLIST:
    430 				prog = getxdr_u_long();
    431 				ver  = getxdr_u_long();
    432 				(void) sprintf(line,
    433 					" prog=%d (%s) vers=%d",
    434 					prog, nameof_prog(prog),
    435 					ver);
    436 				break;
    437 			case RPCBPROC_BCAST:
    438 			case RPCBPROC_INDIRECT:
    439 				(void) getxdr_u_long(); /* length */
    440 				(void) sprintf(line,
    441 					" prog=%s vers=%d proc=%d",
    442 					nameof_prog(iprog),
    443 					ivers, iproc);
    444 				data += 16; /* prog+ver+proc+len */
    445 				len -= 16;
    446 				protoprint(flags, type, xid,
    447 					iprog, ivers, iproc,
    448 					data, len);
    449 				break;
    450 			default:
    451 				break;
    452 			}
    453 
    454 			check_retransmit(line, xid);
    455 		} else {
    456 			(void) sprintf(line, "RPCBIND R %s ",
    457 				procnames_short_4[proc]);
    458 			line += strlen(line);
    459 			switch (proc) {
    460 			case RPCBPROC_GETADDR:
    461 			case RPCBPROC_TADDR2UADDR:
    462 			case RPCBPROC_GETVERSADDR:
    463 				(void) getxdr_string(buff1, MAXSTRINGLEN);
    464 				(void) sprintf(line,
    465 					" Uaddr=%s",
    466 					buff1);
    467 				break;
    468 			case RPCBPROC_BCAST:
    469 			case RPCBPROC_INDIRECT:
    470 				(void) getxdr_string(buff1, MAXSTRINGLEN);
    471 				ilen = getxdr_u_long();
    472 				(void) sprintf(line, "Uaddr=%s len=%d",
    473 					buff1, ilen);
    474 				data += 16; /* prog+ver+proc+len */
    475 				len -= 16;
    476 				if (x != NULL) {
    477 					protoprint(flags, type, xid,
    478 						x->xid_prog,
    479 						x->xid_vers,
    480 						x->xid_proc,
    481 						data, len);
    482 				}
    483 				break;
    484 			case RPCBPROC_DUMP:
    485 				(void) sprintf(line, "%s",
    486 					sum_rpcblist());
    487 				break;
    488 			case RPCBPROC_GETTIME:
    489 				(void) sprintf(line, "%s",
    490 					getxdr_date());
    491 				break;
    492 			case RPCBPROC_GETADDRLIST:
    493 				(void) sprintf(line, "%s",
    494 					sum_rpcb_entry_list());
    495 				break;
    496 			default:
    497 				break;
    498 			}
    499 		}
    500 	}
    501 
    502 	if (flags & F_DTAIL) {
    503 		show_header("RPCB:  ", "RPC Bind", len);
    504 		show_space();
    505 		if (setjmp(xdr_err)) {
    506 			return;
    507 		}
    508 		(void) sprintf(get_line(0, 0),
    509 			"Proc = %d (%s)",
    510 			proc, procnames_long_4[proc]);
    511 		if (type == CALL) {
    512 			switch (proc) {
    513 			case RPCBPROC_NULL:
    514 				break;
    515 			case RPCBPROC_SET:
    516 			case RPCBPROC_UNSET:
    517 			case RPCBPROC_GETADDR:
    518 			case RPCBPROC_GETVERSADDR:
    519 			case RPCBPROC_GETADDRLIST:
    520 				(void) showxdr_u_long("Program = %d");
    521 				(void) showxdr_u_long("Version = %d");
    522 				(void) showxdr_string(64, "Netid   = %s");
    523 				break;
    524 			case RPCBPROC_DUMP:
    525 				break;
    526 			case RPCBPROC_BCAST:
    527 			case RPCBPROC_INDIRECT:
    528 				(void) sprintf(get_line(0, 0),
    529 					"Program = %d (%s)",
    530 					iprog, nameof_prog(iprog));
    531 				(void) sprintf(get_line(0, 0),
    532 					"Version = %d", ivers);
    533 				(void) sprintf(get_line(0, 0),
    534 					"Proc    = %d", iproc);
    535 				(void) showxdr_u_long(
    536 					"Callit data = %d bytes");
    537 				show_trailer();
    538 				trailer_done = 1;
    539 				data += 16; /* prog+ver+proc+len */
    540 				len -= 16;
    541 				protoprint(flags, type, xid,
    542 					iprog, ivers, iproc,
    543 					data, len);
    544 				break;
    545 			case RPCBPROC_GETTIME:
    546 				break;
    547 			case RPCBPROC_UADDR2TADDR:
    548 			case RPCBPROC_TADDR2UADDR:
    549 				break;
    550 			}
    551 		} else {
    552 			switch (proc) {
    553 			case RPCBPROC_NULL:
    554 			case RPCBPROC_SET:
    555 			case RPCBPROC_UNSET:
    556 				break;
    557 			case RPCBPROC_GETADDR:
    558 			case RPCBPROC_TADDR2UADDR:
    559 			case RPCBPROC_GETVERSADDR:
    560 				(void) showxdr_string(64, "Uaddr = %s");
    561 				break;
    562 			case RPCBPROC_DUMP:
    563 				show_rpcblist();
    564 				break;
    565 			case RPCBPROC_BCAST:
    566 			case RPCBPROC_INDIRECT:
    567 				(void) showxdr_string(64, "Uaddr = %s");
    568 				(void) showxdr_u_long("Length = %d bytes");
    569 				show_trailer();
    570 				trailer_done = 1;
    571 				if (x != NULL) {
    572 					protoprint(flags, type, xid,
    573 						x->xid_prog,
    574 						x->xid_vers,
    575 						x->xid_proc,
    576 						data, len);
    577 				}
    578 				break;
    579 			case RPCBPROC_GETTIME:
    580 				(void) showxdr_date("Time = %s");
    581 				break;
    582 			case RPCBPROC_UADDR2TADDR:
    583 				break;
    584 			case RPCBPROC_GETADDRLIST:
    585 				show_rpcb_entry_list();
    586 				break;
    587 			}
    588 		}
    589 		if (!trailer_done)
    590 			show_trailer();
    591 	}
    592 }
    593 
    594 char *
    595 sum_rpcblist()
    596 {
    597 	int maps = 0;
    598 	static char buff[MAXSTRINGLEN + 1];
    599 
    600 	if (setjmp(xdr_err)) {
    601 		(void) sprintf(buff, "%d+ map(s) found", maps);
    602 		return (buff);
    603 	}
    604 
    605 	while (getxdr_u_long()) {
    606 		(void) getxdr_u_long();		/* program */
    607 		(void) getxdr_u_long();		/* version */
    608 		(void) getxdr_string(buff, MAXSTRINGLEN); /* netid */
    609 		(void) getxdr_string(buff, MAXSTRINGLEN); /* uaddr */
    610 		(void) getxdr_string(buff, MAXSTRINGLEN); /* owner */
    611 		maps++;
    612 	}
    613 
    614 	(void) sprintf(buff, "%d map(s) found", maps);
    615 	return (buff);
    616 }
    617 
    618 void
    619 show_rpcblist()
    620 {
    621 	unsigned prog, vers;
    622 	char netid[MAXSTRINGLEN + 1], uaddr[MAXSTRINGLEN + 1];
    623 	char owner[MAXSTRINGLEN + 1];
    624 	int maps = 0;
    625 
    626 	if (setjmp(xdr_err)) {
    627 		(void) sprintf(get_line(0, 0),
    628 			" %d+ maps. (Frame is incomplete)",
    629 			maps);
    630 		return;
    631 	}
    632 
    633 	show_space();
    634 	(void) sprintf(get_line(0, 0),
    635 		" Program Vers Netid        Uaddr              Owner");
    636 
    637 	while (getxdr_u_long()) {
    638 		prog  = getxdr_u_long();
    639 		vers  = getxdr_u_long();
    640 		(void) getxdr_string(netid, MAXSTRINGLEN);
    641 		(void) getxdr_string(uaddr, MAXSTRINGLEN);
    642 		(void) getxdr_string(owner, MAXSTRINGLEN);
    643 		(void) sprintf(get_line(0, 0),
    644 			"%8d%5d %-12s %-18s %-10s (%s)",
    645 			prog, vers,
    646 			netid, uaddr, owner,
    647 			nameof_prog(prog));
    648 		maps++;
    649 	}
    650 
    651 	(void) sprintf(get_line(0, 0), " (%d maps)", maps);
    652 }
    653 
    654 char *
    655 sum_rpcb_entry_list()
    656 {
    657 	int maps = 0;
    658 	static char buff[MAXSTRINGLEN + 1];
    659 
    660 	if (setjmp(xdr_err)) {
    661 		(void) sprintf(buff, "%d+ map(s) found", maps);
    662 		return (buff);
    663 	}
    664 
    665 	while (getxdr_u_long()) {
    666 		(void) getxdr_string(buff, MAXSTRINGLEN); /* maddr	*/
    667 		(void) getxdr_string(buff, MAXSTRINGLEN); /* nc_netid	*/
    668 		(void) getxdr_u_long();			  /* nc_semantics */
    669 		(void) getxdr_string(buff, MAXSTRINGLEN); /* nc_protofmly */
    670 		(void) getxdr_string(buff, MAXSTRINGLEN); /* nc_proto	*/
    671 		maps++;
    672 	}
    673 
    674 	(void) sprintf(buff, "%d map(s) found", maps);
    675 	return (buff);
    676 }
    677 
    678 char *semantics_strs[] = {"", "CLTS", "COTS", "COTS-ORD", "RAW"};
    679 
    680 void
    681 show_rpcb_entry_list()
    682 {
    683 	char maddr[MAXSTRINGLEN + 1], netid[MAXSTRINGLEN + 1];
    684 	char protofmly[MAXSTRINGLEN + 1], proto[MAXSTRINGLEN + 1];
    685 	unsigned sem;
    686 	int maps = 0;
    687 
    688 	if (setjmp(xdr_err)) {
    689 		(void) sprintf(get_line(0, 0),
    690 			" %d+ maps. (Frame is incomplete)",
    691 			maps);
    692 		return;
    693 	}
    694 
    695 	show_space();
    696 	(void) sprintf(get_line(0, 0),
    697 		" Maddr      Netid        Semantics Protofmly Proto");
    698 
    699 	while (getxdr_u_long()) {
    700 		(void) getxdr_string(maddr, MAXSTRINGLEN);
    701 		(void) getxdr_string(netid, MAXSTRINGLEN);
    702 		sem  = getxdr_u_long();
    703 		(void) getxdr_string(protofmly, MAXSTRINGLEN);
    704 		(void) getxdr_string(proto, MAXSTRINGLEN);
    705 		(void) sprintf(get_line(0, 0),
    706 			"%-12s %-12s %-8s %-8s %-8s",
    707 			maddr, netid,
    708 			semantics_strs[sem],
    709 			protofmly, proto);
    710 		maps++;
    711 	}
    712 
    713 	(void) sprintf(get_line(0, 0), " (%d maps)", maps);
    714 }
    715 
    716 #define	CXID_CACHE_SIZE	16
    717 struct cache_struct cxid_cache[CXID_CACHE_SIZE];
    718 struct cache_struct *cxcpfirst	= &cxid_cache[0];
    719 struct cache_struct *cxcp	= &cxid_cache[0];
    720 struct cache_struct *cxcplast   = &cxid_cache[CXID_CACHE_SIZE - 1];
    721 
    722 struct cache_struct *
    723 find_callit(xid)
    724 	ulong_t xid;
    725 {
    726 	struct cache_struct *x;
    727 
    728 	for (x = cxcp; x >= cxcpfirst; x--)
    729 		if (x->xid_num == xid)
    730 			return (x);
    731 	for (x = cxcplast; x > cxcp; x--)
    732 		if (x->xid_num == xid)
    733 			return (x);
    734 	return (NULL);
    735 }
    736 
    737 static void
    738 stash_callit(xid, frame, prog, vers, proc)
    739 	ulong_t xid;
    740 	int frame, prog, vers, proc;
    741 {
    742 	struct cache_struct *x;
    743 
    744 	x = find_callit(xid);
    745 	if (x == NULL) {
    746 		x = cxcp++;
    747 		if (cxcp > cxcplast)
    748 			cxcp = cxcpfirst;
    749 		x->xid_num = xid;
    750 		x->xid_frame = frame;
    751 	}
    752 	x->xid_prog = prog;
    753 	x->xid_vers = vers;
    754 	x->xid_proc = proc;
    755 }
    756