2 * Routines for rpc dissection
3 * Copyright 1999, Uwe Girlich <Uwe.Girlich@philosys.de>
5 * $Id: packet-rpc.c,v 1.7 1999/11/11 16:20:24 nneul Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@unicom.net>
9 * Copyright 1998 Gerald Combs
11 * Copied from packet-smb.c
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
40 #include "conversation.h"
41 #include "packet-rpc.h"
44 const value_string rpc_msg_type[3] = {
46 { RPC_REPLY, "Reply" },
50 const value_string rpc_reply_state[3] = {
51 { MSG_ACCEPTED, "accepted" },
52 { MSG_DENIED, "denied" },
56 const value_string rpc_auth_flavor[5] = {
57 { AUTH_NULL, "AUTH_NULL" },
58 { AUTH_UNIX, "AUTH_UNIX" },
59 { AUTH_SHORT, "AUTH_SHORT" },
60 { AUTH_DES, "AUTH_DES" },
64 const value_string rpc_accept_state[6] = {
65 { SUCCESS, "RPC executed successfully" },
66 { PROG_UNAVAIL, "remote hasn't exported program" },
67 { PROG_MISMATCH, "remote can't support version #" },
68 { PROC_UNAVAIL, "program can't support procedure" },
69 { GARBAGE_ARGS, "procedure can't decode params" },
73 const value_string rpc_reject_state[3] = {
74 { RPC_MISMATCH, "RPC_MISMATCH" },
75 { AUTH_ERROR, "AUTH_ERROR" },
79 const value_string rpc_auth_state[6] = {
80 { AUTH_BADCRED, "bad credential (seal broken)" },
81 { AUTH_REJECTEDCRED, "client must begin new session" },
82 { AUTH_BADVERF, "bad verifier (seal broken)" },
83 { AUTH_REJECTEDVERF, "verifier expired or replayed" },
84 { AUTH_TOOWEAK, "rejected for security reasons" },
89 /* the protocol number */
90 static int proto_rpc = -1;
93 /* Hash table with info on RPC program numbers */
94 GHashTable *rpc_progs;
96 /* Hash table with info on RPC procedure numbers */
97 GHashTable *rpc_procs;
100 /***********************************/
101 /* Hash array with procedure names */
102 /***********************************/
106 rpc_proc_equal(gconstpointer k1, gconstpointer k2)
108 rpc_proc_info_key* key1 = (rpc_proc_info_key*) k1;
109 rpc_proc_info_key* key2 = (rpc_proc_info_key*) k2;
111 return ((key1->prog == key2->prog &&
112 key1->vers == key2->vers &&
113 key1->proc == key2->proc) ?
117 /* calculate a hash key */
119 rpc_proc_hash(gconstpointer k)
121 rpc_proc_info_key* key = (rpc_proc_info_key*) k;
123 return (key->prog ^ (key->vers<<16) ^ (key->proc<<24));
127 /* insert some entries */
129 rpc_init_proc_table(guint prog, guint vers, const vsff *proc_table)
133 for (proc = proc_table ; proc->strptr!=NULL; proc++) {
134 rpc_proc_info_key *key;
135 rpc_proc_info_value *value;
137 key = (rpc_proc_info_key *) g_malloc(sizeof(rpc_proc_info_key));
140 key->proc = proc->value;
142 value = (rpc_proc_info_value *) g_malloc(sizeof(rpc_proc_info_value));
143 value->name = proc->strptr;
144 value->dissect_call = proc->dissect_call;
145 value->dissect_reply = proc->dissect_reply;
147 g_hash_table_insert(rpc_procs,key,value);
151 /*----------------------------------------*/
152 /* end of Hash array with procedure names */
153 /*----------------------------------------*/
156 /*********************************/
157 /* Hash array with program names */
158 /*********************************/
162 rpc_prog_equal(gconstpointer k1, gconstpointer k2)
164 rpc_prog_info_key* key1 = (rpc_prog_info_key*) k1;
165 rpc_prog_info_key* key2 = (rpc_prog_info_key*) k2;
167 return ((key1->prog == key2->prog) ?
172 /* calculate a hash key */
174 rpc_prog_hash(gconstpointer k)
176 rpc_prog_info_key* key = (rpc_prog_info_key*) k;
183 rpc_init_prog(int proto, guint32 prog, int ett)
185 rpc_prog_info_key *key;
186 rpc_prog_info_value *value;
188 key = (rpc_prog_info_key *) g_malloc(sizeof(rpc_prog_info_key));
191 value = (rpc_prog_info_value *) g_malloc(sizeof(rpc_prog_info_value));
192 value->proto = proto;
194 value->progname = proto_registrar_get_abbrev(proto);
196 g_hash_table_insert(rpc_progs,key,value);
199 /*--------------------------------------*/
200 /* end of Hash array with program names */
201 /*--------------------------------------*/
204 /* Placeholder for future dissectors.
205 It should vanish, if they are finally present. Up to this point, this
206 minimal variant serves as a detector for RPC services and can even find
207 request/reply pairs. */
209 #define MNT_PROGRAM 100005
210 #define NLM_PROGRAM 100021
211 #define STAT_PROGRAM 100024
213 static int proto_mnt = -1;
214 static int proto_nlm = -1;
215 static int proto_stat = -1;
217 void init_incomplete_dissect(void)
219 proto_mnt = proto_register_protocol("Mount", "MNT");
220 rpc_init_prog(proto_mnt, MNT_PROGRAM, ETT_MNT);
222 proto_nlm = proto_register_protocol("Network Lock Manager", "NLM");
223 rpc_init_prog(proto_nlm, NLM_PROGRAM, ETT_NLM);
225 proto_stat = proto_register_protocol("Status", "STAT");
226 rpc_init_prog(proto_stat, STAT_PROGRAM, ETT_STAT);
231 * Init the hash tables. It will be called from ethereal_proto_init().
232 * ethereal_proto_init() calls later proto_init(), which calls
233 * register_all_protocols().
234 * The proto_register_<some rpc program> functions use these hash tables
235 * here, so we need this order!
240 rpc_progs = g_hash_table_new(rpc_prog_hash, rpc_prog_equal);
241 rpc_procs = g_hash_table_new(rpc_proc_hash, rpc_proc_equal);
245 /* static array, first quick implementation, I'll switch over to GList soon */
246 rpc_call_info rpc_call_table[RPC_CALL_TABLE_LENGTH];
247 guint32 rpc_call_index = 0;
248 guint32 rpc_call_firstfree = 0;
251 rpc_call_insert(rpc_call_info *call)
253 /* some space left? */
254 if (rpc_call_firstfree<RPC_CALL_TABLE_LENGTH) {
255 /* some space left */
256 /* take the first free entry */
257 rpc_call_index = rpc_call_firstfree;
258 /* increase this limit */
259 rpc_call_firstfree++;
260 /* rpc_call_firstfree may now be RPC_CALL_TABLE_LENGTH */
264 /* the next entry, with wrap around */
265 rpc_call_index = (rpc_call_index+1) % rpc_call_firstfree;
268 /* put the entry in */
269 memcpy(&rpc_call_table[rpc_call_index],call,sizeof(*call));
275 rpc_call_lookup(rpc_call_info *call)
282 rpc_call_table[i].xid == call->xid &&
283 rpc_call_table[i].conversation == call->conversation
285 return &rpc_call_table[i];
287 if (rpc_call_firstfree) {
288 /* decrement by one, go to rpc_call_firstfree-1
289 at the start of the list */
290 i = (i-1+rpc_call_firstfree) % rpc_call_firstfree;
292 } while (i!=rpc_call_index);
298 roundup(unsigned int a)
300 unsigned int mod = a % 4;
301 return a + ((mod)? 4-mod : 0);
306 dissect_rpc_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
307 char* name, char* type)
311 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
312 value = EXTRACT_UINT(pd, offset+0);
315 proto_tree_add_text(tree, offset, 4,
316 "%s (%s): %u", name, type, value);
325 dissect_rpc_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
326 char* name, char* type)
331 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
332 value_high = EXTRACT_UINT(pd, offset+0);
333 value_low = EXTRACT_UINT(pd, offset+4);
337 proto_tree_add_text(tree, offset, 8,
338 "%s (%s): %x%08x", name, type, value_high, value_low);
340 proto_tree_add_text(tree, offset, 8,
341 "%s (%s): %u", name, type, value_low);
350 /* arbitrary limit */
351 #define RPC_STRING_MAXBUF 1024
354 dissect_rpc_string(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
356 proto_item *string_item;
357 proto_tree *string_tree = NULL;
359 guint32 string_length;
361 guint32 string_length_full;
362 char string_buffer[RPC_STRING_MAXBUF];
364 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
365 string_length = EXTRACT_UINT(pd,offset+0);
366 string_length_full = roundup(string_length);
367 string_fill = string_length_full - string_length;
368 if (!BYTES_ARE_IN_FRAME(offset+4,string_length_full)) return offset;
369 if (string_length>=sizeof(string_buffer)) return offset;
370 memcpy(string_buffer,pd+offset+4,string_length);
371 string_buffer[string_length] = '\0';
373 string_item = proto_tree_add_text(tree,offset+0,
374 4+string_length_full,
375 "%s: %s", name, string_buffer);
377 string_tree = proto_item_add_subtree(string_item, ETT_RPC_STRING);
381 proto_tree_add_text(string_tree,offset+0,4,
382 "length: %u", string_length);
383 proto_tree_add_text(string_tree,offset+4,string_length,
384 "text: %s", string_buffer);
386 proto_tree_add_text(string_tree,offset+4+string_length,string_fill,
387 "fill bytes: opaque data");
390 offset += 4 + string_length_full;
395 dissect_rpc_string_item(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hfindex)
397 proto_item *string_item;
398 proto_tree *string_tree = NULL;
400 guint32 string_length;
402 guint32 string_length_full;
403 char string_buffer[RPC_STRING_MAXBUF];
405 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
406 string_length = EXTRACT_UINT(pd,offset+0);
407 string_length_full = roundup(string_length);
408 string_fill = string_length_full - string_length;
409 if (!BYTES_ARE_IN_FRAME(offset+4,string_length_full)) return offset;
410 if (string_length>=sizeof(string_buffer)) return offset;
411 memcpy(string_buffer,pd+offset+4,string_length);
412 string_buffer[string_length] = '\0';
414 string_item = proto_tree_add_text(tree,offset+0,
415 4+string_length_full,
416 "%s: %s", proto_registrar_get_name(hfindex), string_buffer);
417 proto_tree_add_item_hidden(tree, hfindex, offset+4,
418 string_length, string_buffer);
420 string_tree = proto_item_add_subtree(string_item, ETT_RPC_STRING);
424 proto_tree_add_text(string_tree,offset+0,4,
425 "length: %u", string_length);
426 proto_tree_add_text(string_tree,offset+4,string_length,
427 "text: %s", string_buffer);
429 proto_tree_add_text(string_tree,offset+4+string_length,string_fill,
430 "fill bytes: opaque data");
433 offset += 4 + string_length_full;
439 dissect_rpc_auth( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
445 /* both checks are made outside */
446 /* if (!BYTES_ARE_IN_FRAME(offset,8)) return; */
447 flavor = EXTRACT_UINT(pd,offset+0);
448 length = EXTRACT_UINT(pd,offset+4);
449 length_full = roundup(length);
450 /* if (!BYTES_ARE_IN_FRAME(offset+8,full_length)) return; */
453 proto_tree_add_text(tree,offset+0,4,
454 "Flavor: %s (%u)", val_to_str(flavor,rpc_auth_flavor,"Unknown"),flavor);
455 proto_tree_add_text(tree,offset+4,4,
456 "Length: %u", length);
470 proto_tree *gtree = NULL;
472 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
473 stamp = EXTRACT_UINT(pd,offset+0);
475 proto_tree_add_text(tree,offset+0,4,
476 "stamp: 0x%08x", stamp);
479 offset = dissect_rpc_string(pd,offset,fd,tree,"machinename");
481 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
482 uid = EXTRACT_UINT(pd,offset+0);
484 proto_tree_add_text(tree,offset+0,4,
488 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
489 gid = EXTRACT_UINT(pd,offset+0);
491 proto_tree_add_text(tree,offset+0,4,
495 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
496 gids_count = EXTRACT_UINT(pd,offset+0);
498 gitem = proto_tree_add_text(tree, offset, 4+gids_count*4,
500 gtree = proto_item_add_subtree(gitem, ETT_RPC_GIDS);
503 if (!BYTES_ARE_IN_FRAME(offset,4*gids_count)) return;
504 for (gids_i = 0 ; gids_i < gids_count ; gids_i++) {
505 gids_entry = EXTRACT_UINT(pd,offset+0);
507 proto_tree_add_text(gtree, offset, 4,
511 /* how can I NOW change the gitem to print a list with
512 the first 16 gids? */
520 /* I have no tcpdump file with such a packet to verify the
521 info from the RFC 1050 */
530 proto_tree_add_text(tree,offset,
531 length_full, "opaque data");
537 dissect_rpc_cred( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
544 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
545 length = EXTRACT_UINT(pd,offset+4);
546 length_full = roundup(length);
547 if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
550 citem = proto_tree_add_text(tree, offset, 8+length_full,
552 ctree = proto_item_add_subtree(citem, ETT_RPC_CRED);
553 dissect_rpc_auth(pd, offset, fd, ctree);
555 offset += 8 + length_full;
562 dissect_rpc_verf( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
565 unsigned int length_full;
569 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
570 length = EXTRACT_UINT(pd,offset+4);
571 length_full = roundup(length);
572 if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
575 vitem = proto_tree_add_text(tree, offset, 8+length_full,
577 vtree = proto_item_add_subtree(vitem, ETT_RPC_VERF);
578 dissect_rpc_auth(pd, offset, fd, vtree);
580 offset += 8 + length_full;
587 dissect_rpc( const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
588 guint32 msg_type, void* info)
591 unsigned int rpcvers;
593 unsigned int vers = 0;
594 unsigned int proc = 0;
598 unsigned int reply_state;
599 unsigned int accept_state;
600 unsigned int reject_state;
602 char *msg_type_name = NULL;
604 char *procname = NULL;
605 static char procname_static[20];
607 unsigned int vers_low;
608 unsigned int vers_high;
610 unsigned int auth_state;
612 proto_item *rpc_item=NULL;
613 proto_tree *rpc_tree = NULL;
615 proto_item *pitem=NULL;
616 proto_tree *ptree = NULL;
617 int offset_old = offset;
619 rpc_call_info rpc_call_msg;
620 rpc_proc_info_key key;
621 rpc_proc_info_value *value = NULL;
622 conversation_t* conversation;
624 /* the last parameter can be either of these two types */
625 rpc_call_info *rpc_call;
626 rpc_prog_info_key rpc_prog_key;
627 rpc_prog_info_value *rpc_prog;
629 dissect_function_t *dissect_function = NULL;
631 if (check_col(fd, COL_PROTOCOL))
632 col_add_str(fd, COL_PROTOCOL, "RPC");
635 rpc_item = proto_tree_add_item(tree, proto_rpc, offset, END_OF_FRAME, NULL);
637 rpc_tree = proto_item_add_subtree(rpc_item, ETT_RPC);
641 xid = EXTRACT_UINT(pd,offset+0);
643 proto_tree_add_text(rpc_tree,offset+0,4,
644 "XID: 0x%x (%u)", xid, xid);
647 /* we should better compare this with the argument?! */
648 msg_type = EXTRACT_UINT(pd,offset+4);
649 msg_type_name = val_to_str(msg_type,rpc_msg_type,"%u");
651 proto_tree_add_text(rpc_tree,offset+4,4,
653 msg_type_name, msg_type);
658 if (msg_type==RPC_CALL) {
659 /* we know already the proto-entry and the ETT-const */
660 rpc_prog = (rpc_prog_info_value*)info;
661 proto = rpc_prog->proto;
663 progname = rpc_prog->progname;
665 rpcvers = EXTRACT_UINT(pd,offset+0);
667 proto_tree_add_text(rpc_tree,offset+0,4,
668 "RPC Version: %u", rpcvers);
671 prog = EXTRACT_UINT(pd,offset+4);
674 proto_tree_add_text(rpc_tree,offset+4,4,
675 "Program: %s (%u)", progname, prog);
678 if (check_col(fd, COL_PROTOCOL)) {
679 /* Set the protocol name to the underlying
681 col_add_fstr(fd, COL_PROTOCOL, "%s", progname);
684 if (!BYTES_ARE_IN_FRAME(offset+8,4)) return;
685 vers = EXTRACT_UINT(pd,offset+8);
687 proto_tree_add_text(rpc_tree,offset+8,4,
688 "Program Version: %u",vers);
691 if (!BYTES_ARE_IN_FRAME(offset+12,4)) return;
692 proc = EXTRACT_UINT(pd,offset+12);
698 value = g_hash_table_lookup(rpc_procs,&key);
700 dissect_function = value->dissect_call;
701 procname = value->name;
704 /* happens only with strange program versions or
705 non-existing dissectors */
706 dissect_function = NULL;
707 sprintf(procname_static, "proc-%u", proc);
708 procname = procname_static;
711 proto_tree_add_text(rpc_tree,offset+12,4,
712 "Procedure: %s (%u)", procname, proc);
715 if (check_col(fd, COL_INFO)) {
716 col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
723 conversation = find_conversation(&pi.src, &pi.dst, pi.ptype,
724 pi.srcport, pi.destport);
725 if (conversation == NULL) {
726 /* It's not part of any conversation - create a new one. */
727 conversation = conversation_new(&pi.src, &pi.dst, pi.ptype,
728 pi.srcport, pi.destport, NULL);
731 /* prepare the key data */
732 rpc_call_msg.xid = xid;
733 rpc_call_msg.conversation = conversation;
735 /* look up the request */
736 if (rpc_call_lookup(&rpc_call_msg)) {
737 /* duplicate request */
738 if (check_col(fd, COL_INFO)) {
739 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
743 /* prepare the value data */
744 rpc_call_msg.replies = 0;
745 rpc_call_msg.prog = prog;
746 rpc_call_msg.vers = vers;
747 rpc_call_msg.proc = proc;
748 rpc_call_msg.proc_info = value;
750 rpc_call_insert(&rpc_call_msg);
755 offset = dissect_rpc_cred(pd, offset, fd, rpc_tree);
756 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
758 /* go to the next dissector */
759 /* goto dissect_rpc_prog; */
761 } /* end of RPC call */
762 else if (msg_type == RPC_REPLY)
764 /* we know already the type from the calling routine */
765 rpc_call = (rpc_call_info*)info;
766 prog = rpc_call->prog;
767 vers = rpc_call->vers;
768 proc = rpc_call->proc;
769 if (rpc_call->proc_info != NULL) {
770 dissect_function = rpc_call->proc_info->dissect_reply;
771 if (rpc_call->proc_info->name != NULL) {
772 procname = rpc_call->proc_info->name;
775 sprintf(procname_static, "proc-%u", proc);
776 procname = procname_static;
780 dissect_function = NULL;
781 sprintf(procname_static, "proc-%u", proc);
782 procname = procname_static;
786 rpc_prog_key.prog = prog;
787 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
790 progname = "Unknown";
793 proto = rpc_prog->proto;
795 progname = rpc_prog->progname;
797 if (check_col(fd, COL_PROTOCOL)) {
798 /* Set the protocol name to the underlying
800 col_add_fstr(fd, COL_PROTOCOL, "%s",
805 if (check_col(fd, COL_INFO)) {
806 col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
814 proto_tree_add_text(rpc_tree,0,0,
817 proto_tree_add_text(rpc_tree,0,0,
818 "Program Version: %u", vers);
819 proto_tree_add_text(rpc_tree,0,0,
820 "Procedure: %s (%u)", procname, proc);
823 if (rpc_call->replies>1) {
824 if (check_col(fd, COL_INFO)) {
825 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
829 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
830 reply_state = EXTRACT_UINT(pd,offset+0);
832 proto_tree_add_text(rpc_tree,offset+0, 4,
833 "Reply State: %s (%u)",
834 val_to_str(reply_state,rpc_reply_state,"Unknown"),
839 if (reply_state == MSG_ACCEPTED) {
840 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
841 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
842 accept_state = EXTRACT_UINT(pd,offset+0);
844 proto_tree_add_text(rpc_tree,offset+0, 4,
845 "Accept State: %s (%u)",
846 val_to_str(accept_state,rpc_accept_state,"Unknown"),
850 switch (accept_state) {
852 /* now goto the lower protocol */
853 goto dissect_rpc_prog;
856 if (!BYTES_ARE_IN_FRAME(offset,8)) return;
857 vers_low = EXTRACT_UINT(pd,offset+0);
858 vers_high = EXTRACT_UINT(pd,offset+4);
860 proto_tree_add_text(rpc_tree,
862 "min. Program Version: %u",
864 proto_tree_add_text(rpc_tree,
866 "max. Program Version: %u",
875 } else if (reply_state == MSG_DENIED) {
876 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
877 reject_state = EXTRACT_UINT(pd,offset+0);
879 proto_tree_add_text(rpc_tree, offset+0, 4,
880 "Reject State: %s (%u)",
881 val_to_str(reject_state,rpc_reject_state,"Unknown"),
886 if (reject_state==RPC_MISMATCH) {
887 if (!BYTES_ARE_IN_FRAME(offset,8)) return;
888 vers_low = EXTRACT_UINT(pd,offset+0);
889 vers_high = EXTRACT_UINT(pd,offset+4);
891 proto_tree_add_text(rpc_tree,
893 "min. RPC Version: %u",
895 proto_tree_add_text(rpc_tree,
897 "max. RPC Version: %u",
901 } else if (reject_state==AUTH_ERROR) {
902 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
903 auth_state = EXTRACT_UINT(pd,offset+0);
905 proto_tree_add_text(rpc_tree,
907 "Authentication error: %s (%u)",
908 val_to_str(auth_state,rpc_auth_state,"Unknown"),
914 } /* end of RPC reply */
917 /* I know, goto is evil but it works as it is. */
919 /* now we know, that RPC was shorter */
921 proto_item_set_len(rpc_item, offset - offset_old);
924 /* create here the program specific sub-tree */
926 pitem = proto_tree_add_item(tree, proto, offset, END_OF_FRAME);
928 ptree = proto_item_add_subtree(pitem, ett);
931 /* call a specific dissection */
932 if (dissect_function != NULL) {
933 offset = dissect_function(pd, offset, fd, ptree);
936 /* dissect any remaining bytes (incomplete dissection) as pure data in
938 dissect_data(pd, offset, fd, ptree);
941 /* will be called from file.c on every new file open */
943 rpc_init_protocol(void)
946 rpc_call_firstfree = 0;
950 /* will be called once from register.c at startup time */
952 proto_register_rpc(void)
954 proto_rpc = proto_register_protocol("Remote Procedure Call", "rpc");
956 /* please remove this, if all specific dissectors are ready */
957 init_incomplete_dissect();