xref: /illumos-gate/usr/src/cmd/cmd-inet/usr.sbin/snoop/snoop_pmap.c (revision 78fb3df6a49cd4598f9bba9960558158f7ec440a)
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 				(void) sprintf(line, "%s",
496 					getxdr_date());
497 				break;
498 			case RPCBPROC_GETADDRLIST:
499 				(void) sprintf(line, "%s",
500 					sum_rpcb_entry_list());
501 				break;
502 			default:
503 				break;
504 			}
505 		}
506 	}
507 
508 	if (flags & F_DTAIL) {
509 		show_header("RPCB:  ", "RPC Bind", len);
510 		show_space();
511 		if (setjmp(xdr_err)) {
512 			return;
513 		}
514 		(void) sprintf(get_line(0, 0),
515 			"Proc = %d (%s)",
516 			proc, procnames_long_4[proc]);
517 		if (type == CALL) {
518 			switch (proc) {
519 			case RPCBPROC_NULL:
520 				break;
521 			case RPCBPROC_SET:
522 			case RPCBPROC_UNSET:
523 			case RPCBPROC_GETADDR:
524 			case RPCBPROC_GETVERSADDR:
525 			case RPCBPROC_GETADDRLIST:
526 				(void) showxdr_u_long("Program = %d");
527 				(void) showxdr_u_long("Version = %d");
528 				(void) showxdr_string(64, "Netid   = %s");
529 				break;
530 			case RPCBPROC_DUMP:
531 				break;
532 			case RPCBPROC_BCAST:
533 			case RPCBPROC_INDIRECT:
534 				(void) sprintf(get_line(0, 0),
535 					"Program = %d (%s)",
536 					iprog, nameof_prog(iprog));
537 				(void) sprintf(get_line(0, 0),
538 					"Version = %d", ivers);
539 				(void) sprintf(get_line(0, 0),
540 					"Proc    = %d", iproc);
541 				(void) showxdr_u_long(
542 					"Callit data = %d bytes");
543 				show_trailer();
544 				trailer_done = 1;
545 				data += 16; /* prog+ver+proc+len */
546 				len -= 16;
547 				protoprint(flags, type, xid,
548 					iprog, ivers, iproc,
549 					data, len);
550 				break;
551 			case RPCBPROC_GETTIME:
552 				break;
553 			case RPCBPROC_UADDR2TADDR:
554 			case RPCBPROC_TADDR2UADDR:
555 				break;
556 			}
557 		} else {
558 			switch (proc) {
559 			case RPCBPROC_NULL:
560 			case RPCBPROC_SET:
561 			case RPCBPROC_UNSET:
562 				break;
563 			case RPCBPROC_GETADDR:
564 			case RPCBPROC_TADDR2UADDR:
565 			case RPCBPROC_GETVERSADDR:
566 				(void) showxdr_string(64, "Uaddr = %s");
567 				break;
568 			case RPCBPROC_DUMP:
569 				show_rpcblist();
570 				break;
571 			case RPCBPROC_BCAST:
572 			case RPCBPROC_INDIRECT:
573 				(void) showxdr_string(64, "Uaddr = %s");
574 				(void) showxdr_u_long("Length = %d bytes");
575 				show_trailer();
576 				trailer_done = 1;
577 				if (x != NULL) {
578 					protoprint(flags, type, xid,
579 						x->xid_prog,
580 						x->xid_vers,
581 						x->xid_proc,
582 						data, len);
583 				}
584 				break;
585 			case RPCBPROC_GETTIME:
586 				(void) showxdr_date("Time = %s");
587 				break;
588 			case RPCBPROC_UADDR2TADDR:
589 				break;
590 			case RPCBPROC_GETADDRLIST:
591 				show_rpcb_entry_list();
592 				break;
593 			}
594 		}
595 		if (!trailer_done)
596 			show_trailer();
597 	}
598 }
599 
600 char *
601 sum_rpcblist()
602 {
603 	int maps = 0;
604 	static char buff[MAXSTRINGLEN + 1];
605 
606 	if (setjmp(xdr_err)) {
607 		(void) sprintf(buff, "%d+ map(s) found", maps);
608 		return (buff);
609 	}
610 
611 	while (getxdr_u_long()) {
612 		(void) getxdr_u_long();		/* program */
613 		(void) getxdr_u_long();		/* version */
614 		(void) getxdr_string(buff, MAXSTRINGLEN); /* netid */
615 		(void) getxdr_string(buff, MAXSTRINGLEN); /* uaddr */
616 		(void) getxdr_string(buff, MAXSTRINGLEN); /* owner */
617 		maps++;
618 	}
619 
620 	(void) sprintf(buff, "%d map(s) found", maps);
621 	return (buff);
622 }
623 
624 void
625 show_rpcblist()
626 {
627 	unsigned prog, vers;
628 	char netid[MAXSTRINGLEN + 1], uaddr[MAXSTRINGLEN + 1];
629 	char owner[MAXSTRINGLEN + 1];
630 	int maps = 0;
631 
632 	if (setjmp(xdr_err)) {
633 		(void) sprintf(get_line(0, 0),
634 		    " %d+ maps. (Frame is incomplete)",
635 		    maps);
636 		return;
637 	}
638 
639 	show_space();
640 	(void) sprintf(get_line(0, 0),
641 	    " Program Vers Netid        Uaddr              Owner");
642 
643 	while (getxdr_u_long()) {
644 		prog  = getxdr_u_long();
645 		vers  = getxdr_u_long();
646 		(void) getxdr_string(netid, MAXSTRINGLEN);
647 		(void) getxdr_string(uaddr, MAXSTRINGLEN);
648 		(void) getxdr_string(owner, MAXSTRINGLEN);
649 		(void) sprintf(get_line(0, 0),
650 		    "%8d%5d %-12s %-18s %-10s (%s)",
651 		    prog, vers,
652 		    netid, uaddr, owner,
653 		    nameof_prog(prog));
654 		maps++;
655 	}
656 
657 	(void) sprintf(get_line(0, 0), " (%d maps)", maps);
658 }
659 
660 char *
661 sum_rpcb_entry_list()
662 {
663 	int maps = 0;
664 	static char buff[MAXSTRINGLEN + 1];
665 
666 	if (setjmp(xdr_err)) {
667 		(void) sprintf(buff, "%d+ map(s) found", maps);
668 		return (buff);
669 	}
670 
671 	while (getxdr_u_long()) {
672 		(void) getxdr_string(buff, MAXSTRINGLEN); /* maddr	*/
673 		(void) getxdr_string(buff, MAXSTRINGLEN); /* nc_netid	*/
674 		(void) getxdr_u_long();			  /* nc_semantics */
675 		(void) getxdr_string(buff, MAXSTRINGLEN); /* nc_protofmly */
676 		(void) getxdr_string(buff, MAXSTRINGLEN); /* nc_proto	*/
677 		maps++;
678 	}
679 
680 	(void) sprintf(buff, "%d map(s) found", maps);
681 	return (buff);
682 }
683 
684 char *semantics_strs[] = {"", "CLTS", "COTS", "COTS-ORD", "RAW"};
685 
686 void
687 show_rpcb_entry_list()
688 {
689 	char maddr[MAXSTRINGLEN + 1], netid[MAXSTRINGLEN + 1];
690 	char protofmly[MAXSTRINGLEN + 1], proto[MAXSTRINGLEN + 1];
691 	unsigned sem;
692 	int maps = 0;
693 
694 	if (setjmp(xdr_err)) {
695 		(void) sprintf(get_line(0, 0),
696 		    " %d+ maps. (Frame is incomplete)",
697 		    maps);
698 		return;
699 	}
700 
701 	show_space();
702 	(void) sprintf(get_line(0, 0),
703 	    " Maddr      Netid        Semantics Protofmly Proto");
704 
705 	while (getxdr_u_long()) {
706 		(void) getxdr_string(maddr, MAXSTRINGLEN);
707 		(void) getxdr_string(netid, MAXSTRINGLEN);
708 		sem  = getxdr_u_long();
709 		(void) getxdr_string(protofmly, MAXSTRINGLEN);
710 		(void) getxdr_string(proto, MAXSTRINGLEN);
711 		(void) sprintf(get_line(0, 0),
712 		    "%-12s %-12s %-8s %-8s %-8s",
713 		    maddr, netid,
714 		    semantics_strs[sem],
715 		    protofmly, proto);
716 		maps++;
717 	}
718 
719 	(void) sprintf(get_line(0, 0), " (%d maps)", maps);
720 }
721 
722 #define	CXID_CACHE_SIZE	16
723 struct cache_struct cxid_cache[CXID_CACHE_SIZE];
724 struct cache_struct *cxcpfirst	= &cxid_cache[0];
725 struct cache_struct *cxcp	= &cxid_cache[0];
726 struct cache_struct *cxcplast   = &cxid_cache[CXID_CACHE_SIZE - 1];
727 
728 struct cache_struct *
729 find_callit(xid)
730 	ulong_t xid;
731 {
732 	struct cache_struct *x;
733 
734 	for (x = cxcp; x >= cxcpfirst; x--)
735 		if (x->xid_num == xid)
736 			return (x);
737 	for (x = cxcplast; x > cxcp; x--)
738 		if (x->xid_num == xid)
739 			return (x);
740 	return (NULL);
741 }
742 
743 static void
744 stash_callit(xid, frame, prog, vers, proc)
745 	ulong_t xid;
746 	int frame, prog, vers, proc;
747 {
748 	struct cache_struct *x;
749 
750 	x = find_callit(xid);
751 	if (x == NULL) {
752 		x = cxcp++;
753 		if (cxcp > cxcplast)
754 			cxcp = cxcpfirst;
755 		x->xid_num = xid;
756 		x->xid_frame = frame;
757 	}
758 	x->xid_prog = prog;
759 	x->xid_vers = vers;
760 	x->xid_proc = proc;
761 }
762