xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_pmap.c (revision 9b9d39d2a32ff806d2431dbcc50968ef1e6d46b2)
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  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
28  */
29 
30 #include <sys/types.h>
31 #include <sys/errno.h>
32 #include <setjmp.h>
33 #include <sys/tiuser.h>
34 #include <string.h>
35 
36 #include <rpc/types.h>
37 #include <rpc/xdr.h>
38 #include <rpc/auth.h>
39 #include <rpc/clnt.h>
40 #include <rpc/rpc_msg.h>
41 #include <rpc/pmap_prot.h>
42 #include "snoop.h"
43 
44 /*
45  * Number of bytes to display from a string (address, netid, etc.).
46  */
47 #define	MAXSTRINGLEN	64
48 
49 extern char *dlc_header;
50 extern jmp_buf xdr_err;
51 
52 static void interpret_pmap_2(int, int, int, int, int, char *, int);
53 static void interpret_pmap_4(int, int, int, int, int, char *, int);
54 static void stash_callit(ulong_t, int, int, int, int);
55 
56 void
57 interpret_pmap(flags, type, xid, vers, proc, data, len)
58 	int flags, type, xid, vers, proc;
59 	char *data;
60 	int len;
61 {
62 	switch (vers) {
63 	case 2:	interpret_pmap_2(flags, type, xid, vers, proc, data, len);
64 		break;
65 
66 	/* Version 3 is a subset of version 4 */
67 	case 3:
68 	case 4:	interpret_pmap_4(flags, type, xid, vers, proc, data, len);
69 		break;
70 	}
71 }
72 
73 void show_pmap();
74 char *sum_pmaplist();
75 void show_pmaplist();
76 
77 static char *procnames_short_2[] = {
78 	"Null",		/* 0 */
79 	"SET",		/* 1 */
80 	"UNSET",	/* 2 */
81 	"GETPORT",	/* 3 */
82 	"DUMP",		/* 4 */
83 	"CALLIT",	/* 5 */
84 };
85 
86 static char *procnames_long_2[] = {
87 	"Null procedure",	/* 0 */
88 	"Set port",		/* 1 */
89 	"Unset port",		/* 2 */
90 	"Get port number",	/* 3 */
91 	"Dump the mappings",	/* 4 */
92 	"Indirect call",	/* 5 */
93 };
94 
95 #define	MAXPROC_2	5
96 
97 void
98 interpret_pmap_2(flags, type, xid, vers, proc, data, len)
99 	int flags, type, xid, vers, proc;
100 	char *data;
101 	int len;
102 {
103 	char *line;
104 	unsigned port, proto;
105 	unsigned iprog, ivers, iproc, ilen;
106 	extern int pi_frame;
107 	struct cache_struct *x, *find_callit();
108 	int trailer_done = 0;
109 
110 	if (proc < 0 || proc > MAXPROC_2)
111 		return;
112 
113 	if (proc == PMAPPROC_CALLIT) {
114 		if (type == CALL) {
115 			iprog = getxdr_u_long();
116 			ivers = getxdr_u_long();
117 			iproc = getxdr_u_long();
118 			stash_callit(xid, pi_frame, 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, "PORTMAP C %s",
133 			    procnames_short_2[proc]);
134 			line += strlen(line);
135 			switch (proc) {
136 			case PMAPPROC_GETPORT:
137 				iprog = getxdr_u_long();
138 				ivers = getxdr_u_long();
139 				proto = getxdr_u_long();
140 				(void) sprintf(line,
141 				    " prog=%d (%s) vers=%d proto=%s",
142 				    iprog, nameof_prog(iprog),
143 				    ivers,
144 				    getproto(proto));
145 				break;
146 			case PMAPPROC_CALLIT:
147 				(void) sprintf(line,
148 				    " prog=%s vers=%d proc=%d",
149 				    nameof_prog(iprog),
150 				    ivers, iproc);
151 				if (flags & F_ALLSUM) {
152 					(void) getxdr_u_long(); /* length */
153 					data += 16; /* prog+ver+proc+len */
154 					len -= 16;
155 					protoprint(flags, type, xid,
156 					    iprog, ivers, iproc,
157 					    data, len);
158 				}
159 				break;
160 			default:
161 				break;
162 			}
163 			check_retransmit(line, xid);
164 		} else {
165 			(void) sprintf(line, "PORTMAP R %s ",
166 			    procnames_short_2[proc]);
167 			line += strlen(line);
168 			switch (proc) {
169 			case PMAPPROC_GETPORT:
170 				port = getxdr_u_long();
171 				(void) sprintf(line, "port=%d", port);
172 				break;
173 			case PMAPPROC_DUMP:
174 				(void) sprintf(line, "%s", sum_pmaplist());
175 				break;
176 			case PMAPPROC_CALLIT:
177 				port = getxdr_u_long();
178 				ilen = getxdr_u_long();
179 				(void) sprintf(line, "port=%d len=%d",
180 				    port, ilen);
181 				if (flags & F_ALLSUM && x != NULL) {
182 					data += 8; /* port+len */
183 					len -= 8;
184 					protoprint(flags, type, xid,
185 					    x->xid_prog,
186 					    x->xid_vers,
187 					    x->xid_proc,
188 					    data, len);
189 				}
190 				break;
191 			default:
192 				break;
193 			}
194 		}
195 	}
196 
197 	if (flags & F_DTAIL) {
198 		show_header("PMAP:  ", "Portmapper", len);
199 		show_space();
200 		if (setjmp(xdr_err)) {
201 			return;
202 		}
203 		(void) sprintf(get_line(0, 0),
204 			"Proc = %d (%s)",
205 			proc, procnames_long_2[proc]);
206 		if (type == CALL) {
207 			switch (proc) {
208 			case PMAPPROC_NULL:
209 			case PMAPPROC_SET:
210 			case PMAPPROC_UNSET:
211 				break;
212 			case PMAPPROC_GETPORT:
213 				iprog = getxdr_u_long();
214 				(void) sprintf(get_line(0, 0),
215 				    "Program = %d (%s)",
216 				    iprog, nameof_prog(iprog));
217 				(void) showxdr_u_long("Version = %d");
218 				proto = getxdr_u_long();
219 				(void) sprintf(get_line(0, 0),
220 				    "Protocol = %d (%s)",
221 				    proto, getproto(proto));
222 				break;
223 			case PMAPPROC_DUMP:
224 				break;
225 			case PMAPPROC_CALLIT:
226 				(void) sprintf(get_line(0, 0),
227 				    "Program = %d (%s)",
228 				    iprog, nameof_prog(iprog));
229 				(void) sprintf(get_line(0, 0),
230 				    "Version = %d", ivers);
231 				(void) sprintf(get_line(0, 0),
232 				    "Proc    = %d", iproc);
233 				(void) showxdr_u_long("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), " Program Version Protocol   Port");
312 
313 	while (getxdr_u_long()) {
314 		prog  = getxdr_u_long();
315 		vers  = getxdr_u_long();
316 		proto = getxdr_u_long();
317 		port  = getxdr_u_long();
318 		(void) sprintf(get_line(0, 0),
319 		    "%8d%8d%9d%7d  %s",
320 		    prog, vers, proto, port, nameof_prog(prog));
321 		maps++;
322 	}
323 
324 	(void) sprintf(get_line(0, 0), " %d maps", maps);
325 }
326 
327 /*
328  * ******************************************
329  */
330 char *sum_rpcblist();
331 void show_rpcblist();
332 char *sum_rpcb_entry_list();
333 void show_rpcb_entry_list();
334 
335 static char *procnames_short_4[] = {
336 	/*
337 	 * version 3 and 4 procs
338 	 */
339 	"Null",		/* 0 */
340 	"SET",		/* 1 */
341 	"UNSET",	/* 2 */
342 	"GETADDR",	/* 3 */
343 	"DUMP",		/* 4 */
344 	"BCAST",	/* 5 */
345 	"GETTIME",	/* 6 */
346 	"UADDR2TADDR",	/* 7 */
347 	"TADDR2UADDR",	/* 8 */
348 	/*
349 	 * version 4 procs only
350 	 */
351 	"GETVERSADDR",	/* 9 */
352 	"INDIRECT",	/* 10 */
353 	"GETADDRLIST",	/* 11 */
354 	"GETSTAT",	/* 12 */
355 };
356 
357 static char *procnames_long_4[] = {
358 	/*
359 	 * version 3 and 4 procs
360 	 */
361 	"Null procedure",			/* 0 */
362 	"Set address",				/* 1 */
363 	"Unset address",			/* 2 */
364 	"Get address",				/* 3 */
365 	"Dump the mappings",			/* 4 */
366 	"Broadcast call (no error)",		/* 5 */
367 	"Get the time",				/* 6 */
368 	"Universal to transport address",	/* 7 */
369 	"Transport to universal address",	/* 8 */
370 	/*
371 	 * version 4 procs only
372 	 */
373 	"Get address of specific version",	/* 9 */
374 	"Indirect call (return error)",		/* 10 */
375 	"Return addresses of prog/vers",	/* 11 */
376 	"Get statistics",			/* 12 */
377 };
378 
379 #define	MAXPROC_3		8
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 || (vers == 3 && proc > MAXPROC_3))
398 		return;
399 
400 	if (proc == RPCBPROC_BCAST || proc == RPCBPROC_INDIRECT) {
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) sprintf(line,
440 					" prog=%s vers=%d proc=%d",
441 					nameof_prog(iprog),
442 					ivers, iproc);
443 				if (flags & F_ALLSUM) {
444 					(void) getxdr_u_long(); /* length */
445 					data += 16; /* prog+ver+proc+len */
446 					len -= 16;
447 					protoprint(flags, type, xid,
448 						iprog, ivers, iproc,
449 						data, len);
450 				}
451 				break;
452 			default:
453 				break;
454 			}
455 
456 			check_retransmit(line, xid);
457 		} else {
458 			int pos;
459 
460 			(void) sprintf(line, "RPCBIND R %s ",
461 				procnames_short_4[proc]);
462 			line += strlen(line);
463 			switch (proc) {
464 			case RPCBPROC_GETADDR:
465 			case RPCBPROC_TADDR2UADDR:
466 			case RPCBPROC_GETVERSADDR:
467 				(void) getxdr_string(buff1, MAXSTRINGLEN);
468 				(void) sprintf(line,
469 					" Uaddr=%s",
470 					buff1);
471 				break;
472 			case RPCBPROC_BCAST:
473 			case RPCBPROC_INDIRECT:
474 				pos = getxdr_pos();
475 				(void) getxdr_string(buff1, MAXSTRINGLEN);
476 				ilen = getxdr_u_long();
477 				(void) sprintf(line, "Uaddr=%s len=%d",
478 					buff1, ilen);
479 				if (flags & F_ALLSUM && x != NULL) {
480 					pos = getxdr_pos() - pos;
481 					data += pos; /* uaddr+len */
482 					len -= pos;
483 					protoprint(flags, type, xid,
484 						x->xid_prog,
485 						x->xid_vers,
486 						x->xid_proc,
487 						data, len);
488 				}
489 				break;
490 			case RPCBPROC_DUMP:
491 				(void) sprintf(line, "%s",
492 					sum_rpcblist());
493 				break;
494 			case RPCBPROC_GETTIME:
495 				{
496 					time_t sec = getxdr_long();
497 					struct tm *tmp = gmtime(&sec);
498 					(void) strftime(line, MAXLINE,
499 					    "%d-%h-%y %T GMT", tmp);
500 				}
501 				break;
502 			case RPCBPROC_GETADDRLIST:
503 				(void) sprintf(line, "%s",
504 					sum_rpcb_entry_list());
505 				break;
506 			default:
507 				break;
508 			}
509 		}
510 	}
511 
512 	if (flags & F_DTAIL) {
513 		show_header("RPCB:  ", "RPC Bind", len);
514 		show_space();
515 		if (setjmp(xdr_err)) {
516 			return;
517 		}
518 		(void) sprintf(get_line(0, 0),
519 			"Proc = %d (%s)",
520 			proc, procnames_long_4[proc]);
521 		if (type == CALL) {
522 			switch (proc) {
523 			case RPCBPROC_NULL:
524 				break;
525 			case RPCBPROC_SET:
526 			case RPCBPROC_UNSET:
527 			case RPCBPROC_GETADDR:
528 			case RPCBPROC_GETVERSADDR:
529 			case RPCBPROC_GETADDRLIST:
530 				(void) showxdr_u_long("Program = %d");
531 				(void) showxdr_u_long("Version = %d");
532 				(void) showxdr_string(64, "Netid   = %s");
533 				break;
534 			case RPCBPROC_DUMP:
535 				break;
536 			case RPCBPROC_BCAST:
537 			case RPCBPROC_INDIRECT:
538 				(void) sprintf(get_line(0, 0),
539 					"Program = %d (%s)",
540 					iprog, nameof_prog(iprog));
541 				(void) sprintf(get_line(0, 0),
542 					"Version = %d", ivers);
543 				(void) sprintf(get_line(0, 0),
544 					"Proc    = %d", iproc);
545 				(void) showxdr_u_long(
546 					"Callit data = %d bytes");
547 				show_trailer();
548 				trailer_done = 1;
549 				data += 16; /* prog+ver+proc+len */
550 				len -= 16;
551 				protoprint(flags, type, xid,
552 					iprog, ivers, iproc,
553 					data, len);
554 				break;
555 			case RPCBPROC_GETTIME:
556 				break;
557 			case RPCBPROC_UADDR2TADDR:
558 			case RPCBPROC_TADDR2UADDR:
559 				break;
560 			}
561 		} else {
562 			switch (proc) {
563 			case RPCBPROC_NULL:
564 			case RPCBPROC_SET:
565 			case RPCBPROC_UNSET:
566 				break;
567 			case RPCBPROC_GETADDR:
568 			case RPCBPROC_TADDR2UADDR:
569 			case RPCBPROC_GETVERSADDR:
570 				(void) showxdr_string(64, "Uaddr = %s");
571 				break;
572 			case RPCBPROC_DUMP:
573 				show_rpcblist();
574 				break;
575 			case RPCBPROC_BCAST:
576 			case RPCBPROC_INDIRECT:
577 				(void) showxdr_string(64, "Uaddr = %s");
578 				(void) showxdr_u_long("Length = %d bytes");
579 				show_trailer();
580 				trailer_done = 1;
581 				if (x != NULL) {
582 					protoprint(flags, type, xid,
583 						x->xid_prog,
584 						x->xid_vers,
585 						x->xid_proc,
586 						data, len);
587 				}
588 				break;
589 			case RPCBPROC_GETTIME:
590 				{
591 					int pos = getxdr_pos();
592 					time_t sec = getxdr_long();
593 					struct tm *tmp = gmtime(&sec);
594 					(void) strftime(get_line(pos,
595 					    getxdr_pos()), MAXLINE,
596 					    "Time = %d-%h-%y %T GMT", tmp);
597 				}
598 				break;
599 			case RPCBPROC_UADDR2TADDR:
600 				break;
601 			case RPCBPROC_GETADDRLIST:
602 				show_rpcb_entry_list();
603 				break;
604 			}
605 		}
606 		if (!trailer_done)
607 			show_trailer();
608 	}
609 }
610 
611 char *
612 sum_rpcblist()
613 {
614 	int maps = 0;
615 	static char buff[MAXSTRINGLEN + 1];
616 
617 	if (setjmp(xdr_err)) {
618 		(void) sprintf(buff, "%d+ map(s) found", maps);
619 		return (buff);
620 	}
621 
622 	while (getxdr_u_long()) {
623 		(void) getxdr_u_long();		/* program */
624 		(void) getxdr_u_long();		/* version */
625 		(void) getxdr_string(buff, MAXSTRINGLEN); /* netid */
626 		(void) getxdr_string(buff, MAXSTRINGLEN); /* uaddr */
627 		(void) getxdr_string(buff, MAXSTRINGLEN); /* owner */
628 		maps++;
629 	}
630 
631 	(void) sprintf(buff, "%d map(s) found", maps);
632 	return (buff);
633 }
634 
635 void
636 show_rpcblist()
637 {
638 	unsigned prog, vers;
639 	char netid[MAXSTRINGLEN + 1], uaddr[MAXSTRINGLEN + 1];
640 	char owner[MAXSTRINGLEN + 1];
641 	int maps = 0;
642 
643 	if (setjmp(xdr_err)) {
644 		(void) sprintf(get_line(0, 0),
645 		    " %d+ maps. (Frame is incomplete)",
646 		    maps);
647 		return;
648 	}
649 
650 	show_space();
651 	(void) sprintf(get_line(0, 0),
652 	    " Program Vers Netid        Uaddr              Owner");
653 
654 	while (getxdr_u_long()) {
655 		prog  = getxdr_u_long();
656 		vers  = getxdr_u_long();
657 		(void) getxdr_string(netid, MAXSTRINGLEN);
658 		(void) getxdr_string(uaddr, MAXSTRINGLEN);
659 		(void) getxdr_string(owner, MAXSTRINGLEN);
660 		(void) sprintf(get_line(0, 0),
661 		    "%8d%5d %-12s %-18s %-10s (%s)",
662 		    prog, vers,
663 		    netid, uaddr, owner,
664 		    nameof_prog(prog));
665 		maps++;
666 	}
667 
668 	(void) sprintf(get_line(0, 0), " (%d maps)", maps);
669 }
670 
671 char *
672 sum_rpcb_entry_list()
673 {
674 	int maps = 0;
675 	static char buff[MAXSTRINGLEN + 1];
676 
677 	if (setjmp(xdr_err)) {
678 		(void) sprintf(buff, "%d+ map(s) found", maps);
679 		return (buff);
680 	}
681 
682 	while (getxdr_u_long()) {
683 		(void) getxdr_string(buff, MAXSTRINGLEN); /* maddr	*/
684 		(void) getxdr_string(buff, MAXSTRINGLEN); /* nc_netid	*/
685 		(void) getxdr_u_long();			  /* nc_semantics */
686 		(void) getxdr_string(buff, MAXSTRINGLEN); /* nc_protofmly */
687 		(void) getxdr_string(buff, MAXSTRINGLEN); /* nc_proto	*/
688 		maps++;
689 	}
690 
691 	(void) sprintf(buff, "%d map(s) found", maps);
692 	return (buff);
693 }
694 
695 char *semantics_strs[] = {"", "CLTS", "COTS", "COTS-ORD", "RAW"};
696 
697 void
698 show_rpcb_entry_list()
699 {
700 	char maddr[MAXSTRINGLEN + 1], netid[MAXSTRINGLEN + 1];
701 	char protofmly[MAXSTRINGLEN + 1], proto[MAXSTRINGLEN + 1];
702 	unsigned sem;
703 	int maps = 0;
704 
705 	if (setjmp(xdr_err)) {
706 		(void) sprintf(get_line(0, 0),
707 		    " %d+ maps. (Frame is incomplete)",
708 		    maps);
709 		return;
710 	}
711 
712 	show_space();
713 	(void) sprintf(get_line(0, 0),
714 	    " Maddr      Netid        Semantics Protofmly Proto");
715 
716 	while (getxdr_u_long()) {
717 		(void) getxdr_string(maddr, MAXSTRINGLEN);
718 		(void) getxdr_string(netid, MAXSTRINGLEN);
719 		sem  = getxdr_u_long();
720 		(void) getxdr_string(protofmly, MAXSTRINGLEN);
721 		(void) getxdr_string(proto, MAXSTRINGLEN);
722 		(void) sprintf(get_line(0, 0),
723 		    "%-12s %-12s %-8s %-8s %-8s",
724 		    maddr, netid,
725 		    semantics_strs[sem],
726 		    protofmly, proto);
727 		maps++;
728 	}
729 
730 	(void) sprintf(get_line(0, 0), " (%d maps)", maps);
731 }
732 
733 #define	CXID_CACHE_SIZE	16
734 struct cache_struct cxid_cache[CXID_CACHE_SIZE];
735 struct cache_struct *cxcpfirst	= &cxid_cache[0];
736 struct cache_struct *cxcp	= &cxid_cache[0];
737 struct cache_struct *cxcplast   = &cxid_cache[CXID_CACHE_SIZE - 1];
738 
739 struct cache_struct *
740 find_callit(xid)
741 	ulong_t xid;
742 {
743 	struct cache_struct *x;
744 
745 	for (x = cxcp; x >= cxcpfirst; x--)
746 		if (x->xid_num == xid)
747 			return (x);
748 	for (x = cxcplast; x > cxcp; x--)
749 		if (x->xid_num == xid)
750 			return (x);
751 	return (NULL);
752 }
753 
754 static void
755 stash_callit(xid, frame, prog, vers, proc)
756 	ulong_t xid;
757 	int frame, prog, vers, proc;
758 {
759 	struct cache_struct *x;
760 
761 	x = find_callit(xid);
762 	if (x == NULL) {
763 		x = cxcp++;
764 		if (cxcp > cxcplast)
765 			cxcp = cxcpfirst;
766 		x->xid_num = xid;
767 		x->xid_frame = frame;
768 	}
769 	x->xid_prog = prog;
770 	x->xid_vers = vers;
771 	x->xid_proc = proc;
772 }
773