2 * Routines for rpc dissection
3 * Copyright 1999, Uwe Girlich <Uwe.Girlich@philosys.de>
5 * $Id: packet-rpc.c,v 1.10 1999/11/14 20:44:52 guy 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 /* return the name associated with a previously registered program. This
200 should probably eventually be expanded to use the rpc YP/NIS map
201 so that it can give names for programs not handled by ethereal */
202 char *rpc_prog_name(guint32 prog)
204 char *progname = NULL;
205 rpc_prog_info_key rpc_prog_key;
206 rpc_prog_info_value *rpc_prog;
208 rpc_prog_key.prog = prog;
209 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
210 progname = "Unknown";
213 progname = rpc_prog->progname;
219 /*--------------------------------------*/
220 /* end of Hash array with program names */
221 /*--------------------------------------*/
224 /* Placeholder for future dissectors.
225 It should vanish, if they are finally present. Up to this point, this
226 minimal variant serves as a detector for RPC services and can even find
227 request/reply pairs. */
229 #define NLM_PROGRAM 100021
231 static int proto_nlm = -1;
233 void init_incomplete_dissect(void)
235 proto_nlm = proto_register_protocol("Network Lock Manager", "NLM");
236 rpc_init_prog(proto_nlm, NLM_PROGRAM, ETT_NLM);
241 * Init the hash tables. It will be called from ethereal_proto_init().
242 * ethereal_proto_init() calls later proto_init(), which calls
243 * register_all_protocols().
244 * The proto_register_<some rpc program> functions use these hash tables
245 * here, so we need this order!
250 rpc_progs = g_hash_table_new(rpc_prog_hash, rpc_prog_equal);
251 rpc_procs = g_hash_table_new(rpc_proc_hash, rpc_proc_equal);
255 /* static array, first quick implementation, I'll switch over to GList soon */
256 rpc_call_info rpc_call_table[RPC_CALL_TABLE_LENGTH];
257 guint32 rpc_call_index = 0;
258 guint32 rpc_call_firstfree = 0;
261 rpc_call_insert(rpc_call_info *call)
263 /* some space left? */
264 if (rpc_call_firstfree<RPC_CALL_TABLE_LENGTH) {
265 /* some space left */
266 /* take the first free entry */
267 rpc_call_index = rpc_call_firstfree;
268 /* increase this limit */
269 rpc_call_firstfree++;
270 /* rpc_call_firstfree may now be RPC_CALL_TABLE_LENGTH */
274 /* the next entry, with wrap around */
275 rpc_call_index = (rpc_call_index+1) % rpc_call_firstfree;
278 /* put the entry in */
279 memcpy(&rpc_call_table[rpc_call_index],call,sizeof(*call));
285 rpc_call_lookup(rpc_call_info *call)
292 rpc_call_table[i].xid == call->xid &&
293 rpc_call_table[i].conversation == call->conversation
295 return &rpc_call_table[i];
297 if (rpc_call_firstfree) {
298 /* decrement by one, go to rpc_call_firstfree-1
299 at the start of the list */
300 i = (i-1+rpc_call_firstfree) % rpc_call_firstfree;
302 } while (i!=rpc_call_index);
308 roundup(unsigned int a)
310 unsigned int mod = a % 4;
311 return a + ((mod)? 4-mod : 0);
316 dissect_rpc_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
317 char* name, char* type)
321 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
322 value = EXTRACT_UINT(pd, offset+0);
325 proto_tree_add_text(tree, offset, 4,
326 "%s (%s): %u", name, type, value);
335 dissect_rpc_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
336 char* name, char* type)
341 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
342 value_high = EXTRACT_UINT(pd, offset+0);
343 value_low = EXTRACT_UINT(pd, offset+4);
347 proto_tree_add_text(tree, offset, 8,
348 "%s (%s): %x%08x", name, type, value_high, value_low);
350 proto_tree_add_text(tree, offset, 8,
351 "%s (%s): %u", name, type, value_low);
360 /* arbitrary limit */
361 #define RPC_STRING_MAXBUF 2048
364 dissect_rpc_string(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
366 proto_item *string_item;
367 proto_tree *string_tree = NULL;
369 guint32 string_length;
371 guint32 string_length_full;
372 char string_buffer[RPC_STRING_MAXBUF];
374 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
375 string_length = EXTRACT_UINT(pd,offset+0);
376 string_length_full = roundup(string_length);
377 string_fill = string_length_full - string_length;
378 if (!BYTES_ARE_IN_FRAME(offset+4,string_length_full)) return offset;
379 if (string_length>=sizeof(string_buffer)) return offset;
380 memcpy(string_buffer,pd+offset+4,string_length);
381 string_buffer[string_length] = '\0';
383 string_item = proto_tree_add_text(tree,offset+0,
384 4+string_length_full,
385 "%s: %s", name, string_buffer);
387 string_tree = proto_item_add_subtree(string_item, ETT_RPC_STRING);
391 proto_tree_add_text(string_tree,offset+0,4,
392 "length: %u", string_length);
393 proto_tree_add_text(string_tree,offset+4,string_length,
394 "text: %s", string_buffer);
396 proto_tree_add_text(string_tree,offset+4+string_length,string_fill,
397 "fill bytes: opaque data");
400 offset += 4 + string_length_full;
405 dissect_rpc_string_item(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, int hfindex)
407 proto_item *string_item;
408 proto_tree *string_tree = NULL;
410 guint32 string_length;
412 guint32 string_length_full;
413 char string_buffer[RPC_STRING_MAXBUF];
415 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
416 string_length = EXTRACT_UINT(pd,offset+0);
417 string_length_full = roundup(string_length);
418 string_fill = string_length_full - string_length;
419 if (!BYTES_ARE_IN_FRAME(offset+4,string_length_full)) return offset;
420 if (string_length>=sizeof(string_buffer)) return offset;
421 memcpy(string_buffer,pd+offset+4,string_length);
422 string_buffer[string_length] = '\0';
424 string_item = proto_tree_add_text(tree,offset+0,
425 4+string_length_full,
426 "%s: %s", proto_registrar_get_name(hfindex), string_buffer);
427 proto_tree_add_item_hidden(tree, hfindex, offset+4,
428 string_length, string_buffer);
430 string_tree = proto_item_add_subtree(string_item, ETT_RPC_STRING);
434 proto_tree_add_text(string_tree,offset+0,4,
435 "length: %u", string_length);
436 proto_tree_add_text(string_tree,offset+4,string_length,
437 "text: %s", string_buffer);
439 proto_tree_add_text(string_tree,offset+4+string_length,string_fill,
440 "fill bytes: opaque data");
443 offset += 4 + string_length_full;
449 dissect_rpc_auth( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
455 /* both checks are made outside */
456 /* if (!BYTES_ARE_IN_FRAME(offset,8)) return; */
457 flavor = EXTRACT_UINT(pd,offset+0);
458 length = EXTRACT_UINT(pd,offset+4);
459 length_full = roundup(length);
460 /* if (!BYTES_ARE_IN_FRAME(offset+8,full_length)) return; */
463 proto_tree_add_text(tree,offset+0,4,
464 "Flavor: %s (%u)", val_to_str(flavor,rpc_auth_flavor,"Unknown"),flavor);
465 proto_tree_add_text(tree,offset+4,4,
466 "Length: %u", length);
480 proto_tree *gtree = NULL;
482 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
483 stamp = EXTRACT_UINT(pd,offset+0);
485 proto_tree_add_text(tree,offset+0,4,
486 "stamp: 0x%08x", stamp);
489 offset = dissect_rpc_string(pd,offset,fd,tree,"machinename");
491 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
492 uid = EXTRACT_UINT(pd,offset+0);
494 proto_tree_add_text(tree,offset+0,4,
498 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
499 gid = EXTRACT_UINT(pd,offset+0);
501 proto_tree_add_text(tree,offset+0,4,
505 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
506 gids_count = EXTRACT_UINT(pd,offset+0);
508 gitem = proto_tree_add_text(tree, offset, 4+gids_count*4,
510 gtree = proto_item_add_subtree(gitem, ETT_RPC_GIDS);
513 if (!BYTES_ARE_IN_FRAME(offset,4*gids_count)) return;
514 for (gids_i = 0 ; gids_i < gids_count ; gids_i++) {
515 gids_entry = EXTRACT_UINT(pd,offset+0);
517 proto_tree_add_text(gtree, offset, 4,
521 /* how can I NOW change the gitem to print a list with
522 the first 16 gids? */
530 /* I have no tcpdump file with such a packet to verify the
531 info from the RFC 1050 */
540 proto_tree_add_text(tree,offset,
541 length_full, "opaque data");
547 dissect_rpc_cred( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
554 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
555 length = EXTRACT_UINT(pd,offset+4);
556 length_full = roundup(length);
557 if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
560 citem = proto_tree_add_text(tree, offset, 8+length_full,
562 ctree = proto_item_add_subtree(citem, ETT_RPC_CRED);
563 dissect_rpc_auth(pd, offset, fd, ctree);
565 offset += 8 + length_full;
572 dissect_rpc_verf( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
575 unsigned int length_full;
579 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
580 length = EXTRACT_UINT(pd,offset+4);
581 length_full = roundup(length);
582 if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
585 vitem = proto_tree_add_text(tree, offset, 8+length_full,
587 vtree = proto_item_add_subtree(vitem, ETT_RPC_VERF);
588 dissect_rpc_auth(pd, offset, fd, vtree);
590 offset += 8 + length_full;
597 dissect_rpc( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
600 rpc_call_info rpc_key;
601 rpc_call_info *rpc_call = NULL;
602 rpc_prog_info_value *rpc_prog = NULL;
603 rpc_prog_info_key rpc_prog_key;
606 unsigned int rpcvers;
608 unsigned int vers = 0;
609 unsigned int proc = 0;
613 unsigned int reply_state;
614 unsigned int accept_state;
615 unsigned int reject_state;
617 char *msg_type_name = NULL;
619 char *procname = NULL;
620 static char procname_static[20];
622 unsigned int vers_low;
623 unsigned int vers_high;
625 unsigned int auth_state;
627 proto_item *rpc_item=NULL;
628 proto_tree *rpc_tree = NULL;
630 proto_item *pitem=NULL;
631 proto_tree *ptree = NULL;
632 int offset_old = offset;
634 rpc_call_info rpc_call_msg;
635 rpc_proc_info_key key;
636 rpc_proc_info_value *value = NULL;
637 conversation_t* conversation;
639 dissect_function_t *dissect_function = NULL;
642 * Check to see whether this looks like an RPC call or reply.
644 if (!BYTES_ARE_IN_FRAME(offset,8)) {
645 /* Captured data in packet isn't enough to let us tell. */
649 /* both directions need at least this */
650 msg_type = EXTRACT_UINT(pd,offset+4);
655 /* check for RPC call */
656 if (!BYTES_ARE_IN_FRAME(offset,16)) {
657 /* Captured data in packet isn't enough to let us
662 /* XID can be anything, we don't check it.
663 We already have the message type.
664 Check whether an RPC version number of 2 is in the
665 location where it would be, and that an RPC program
666 number we know about is in the locaton where it would be. */
667 rpc_prog_key.prog = EXTRACT_UINT(pd,offset+12);
668 if (EXTRACT_UINT(pd,offset+8) != 2 ||
669 ((rpc_prog = g_hash_table_lookup(rpc_progs, &rpc_prog_key))
671 /* They're not, so it's probably not an RPC call. */
677 /* check for RPC reply */
678 conversation = find_conversation(&pi.src, &pi.dst,
679 pi.ptype, pi.srcport, pi.destport);
680 if (conversation == NULL) {
681 /* We haven't seen an RPC call for that conversation,
682 so we can't check for a reply to that call. */
685 rpc_key.xid = EXTRACT_UINT(pd,offset+0);
686 rpc_key.conversation = conversation;
687 if ((rpc_call = rpc_call_lookup(&rpc_key)) == NULL) {
688 /* The XID doesn't match a call from that
689 conversation, so it's probably not an RPC reply. */
695 /* The putative message type field contains neither
696 RPC_CALL nor RPC_REPLY, so it's not an RPC call or
701 if (check_col(fd, COL_PROTOCOL))
702 col_add_str(fd, COL_PROTOCOL, "RPC");
705 rpc_item = proto_tree_add_item(tree, proto_rpc, offset, END_OF_FRAME, NULL);
707 rpc_tree = proto_item_add_subtree(rpc_item, ETT_RPC);
711 xid = EXTRACT_UINT(pd,offset+0);
713 proto_tree_add_text(rpc_tree,offset+0,4,
714 "XID: 0x%x (%u)", xid, xid);
717 msg_type_name = val_to_str(msg_type,rpc_msg_type,"%u");
719 proto_tree_add_text(rpc_tree,offset+4,4,
721 msg_type_name, msg_type);
726 if (msg_type==RPC_CALL) {
727 /* we know already the proto-entry, the ETT-const,
729 proto = rpc_prog->proto;
731 progname = rpc_prog->progname;
733 rpcvers = EXTRACT_UINT(pd,offset+0);
735 proto_tree_add_text(rpc_tree,offset+0,4,
736 "RPC Version: %u", rpcvers);
739 prog = EXTRACT_UINT(pd,offset+4);
742 proto_tree_add_text(rpc_tree,offset+4,4,
743 "Program: %s (%u)", progname, prog);
746 if (check_col(fd, COL_PROTOCOL)) {
747 /* Set the protocol name to the underlying
749 col_add_fstr(fd, COL_PROTOCOL, "%s", progname);
752 if (!BYTES_ARE_IN_FRAME(offset+8,4))
754 vers = EXTRACT_UINT(pd,offset+8);
756 proto_tree_add_text(rpc_tree,offset+8,4,
757 "Program Version: %u",vers);
760 if (!BYTES_ARE_IN_FRAME(offset+12,4))
762 proc = EXTRACT_UINT(pd,offset+12);
768 value = g_hash_table_lookup(rpc_procs,&key);
770 dissect_function = value->dissect_call;
771 procname = value->name;
774 /* happens only with strange program versions or
775 non-existing dissectors */
776 dissect_function = NULL;
777 sprintf(procname_static, "proc-%u", proc);
778 procname = procname_static;
781 proto_tree_add_text(rpc_tree,offset+12,4,
782 "Procedure: %s (%u)", procname, proc);
785 if (check_col(fd, COL_INFO)) {
786 col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
793 conversation = find_conversation(&pi.src, &pi.dst, pi.ptype,
794 pi.srcport, pi.destport);
795 if (conversation == NULL) {
796 /* It's not part of any conversation - create a new one. */
797 conversation = conversation_new(&pi.src, &pi.dst, pi.ptype,
798 pi.srcport, pi.destport, NULL);
801 /* prepare the key data */
802 rpc_call_msg.xid = xid;
803 rpc_call_msg.conversation = conversation;
805 /* look up the request */
806 if (rpc_call_lookup(&rpc_call_msg)) {
807 /* duplicate request */
808 if (check_col(fd, COL_INFO)) {
809 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
813 /* prepare the value data */
814 rpc_call_msg.replies = 0;
815 rpc_call_msg.prog = prog;
816 rpc_call_msg.vers = vers;
817 rpc_call_msg.proc = proc;
818 rpc_call_msg.proc_info = value;
820 rpc_call_insert(&rpc_call_msg);
825 offset = dissect_rpc_cred(pd, offset, fd, rpc_tree);
826 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
828 /* go to the next dissector */
829 /* goto dissect_rpc_prog; */
831 } /* end of RPC call */
832 else if (msg_type == RPC_REPLY)
834 /* we know already the type from the calling routine,
835 and we already have "rpc_call" set above. */
836 prog = rpc_call->prog;
837 vers = rpc_call->vers;
838 proc = rpc_call->proc;
839 if (rpc_call->proc_info != NULL) {
840 dissect_function = rpc_call->proc_info->dissect_reply;
841 if (rpc_call->proc_info->name != NULL) {
842 procname = rpc_call->proc_info->name;
845 sprintf(procname_static, "proc-%u", proc);
846 procname = procname_static;
850 dissect_function = NULL;
851 sprintf(procname_static, "proc-%u", proc);
852 procname = procname_static;
856 rpc_prog_key.prog = prog;
857 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
860 progname = "Unknown";
863 proto = rpc_prog->proto;
865 progname = rpc_prog->progname;
867 if (check_col(fd, COL_PROTOCOL)) {
868 /* Set the protocol name to the underlying
870 col_add_fstr(fd, COL_PROTOCOL, "%s",
875 if (check_col(fd, COL_INFO)) {
876 col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
884 proto_tree_add_text(rpc_tree,0,0,
887 proto_tree_add_text(rpc_tree,0,0,
888 "Program Version: %u", vers);
889 proto_tree_add_text(rpc_tree,0,0,
890 "Procedure: %s (%u)", procname, proc);
893 if (rpc_call->replies>1) {
894 if (check_col(fd, COL_INFO)) {
895 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
899 if (!BYTES_ARE_IN_FRAME(offset,4))
901 reply_state = EXTRACT_UINT(pd,offset+0);
903 proto_tree_add_text(rpc_tree,offset+0, 4,
904 "Reply State: %s (%u)",
905 val_to_str(reply_state,rpc_reply_state,"Unknown"),
910 if (reply_state == MSG_ACCEPTED) {
911 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
912 if (!BYTES_ARE_IN_FRAME(offset,4))
914 accept_state = EXTRACT_UINT(pd,offset+0);
916 proto_tree_add_text(rpc_tree,offset+0, 4,
917 "Accept State: %s (%u)",
918 val_to_str(accept_state,rpc_accept_state,"Unknown"),
922 switch (accept_state) {
924 /* now goto the lower protocol */
925 goto dissect_rpc_prog;
928 if (!BYTES_ARE_IN_FRAME(offset,8))
930 vers_low = EXTRACT_UINT(pd,offset+0);
931 vers_high = EXTRACT_UINT(pd,offset+4);
933 proto_tree_add_text(rpc_tree,
935 "min. Program Version: %u",
937 proto_tree_add_text(rpc_tree,
939 "max. Program Version: %u",
948 } else if (reply_state == MSG_DENIED) {
949 if (!BYTES_ARE_IN_FRAME(offset,4))
951 reject_state = EXTRACT_UINT(pd,offset+0);
953 proto_tree_add_text(rpc_tree, offset+0, 4,
954 "Reject State: %s (%u)",
955 val_to_str(reject_state,rpc_reject_state,"Unknown"),
960 if (reject_state==RPC_MISMATCH) {
961 if (!BYTES_ARE_IN_FRAME(offset,8))
963 vers_low = EXTRACT_UINT(pd,offset+0);
964 vers_high = EXTRACT_UINT(pd,offset+4);
966 proto_tree_add_text(rpc_tree,
968 "min. RPC Version: %u",
970 proto_tree_add_text(rpc_tree,
972 "max. RPC Version: %u",
976 } else if (reject_state==AUTH_ERROR) {
977 if (!BYTES_ARE_IN_FRAME(offset,4))
979 auth_state = EXTRACT_UINT(pd,offset+0);
981 proto_tree_add_text(rpc_tree,
983 "Authentication error: %s (%u)",
984 val_to_str(auth_state,rpc_auth_state,"Unknown"),
990 } /* end of RPC reply */
993 /* I know, goto is evil but it works as it is. */
995 /* now we know, that RPC was shorter */
997 proto_item_set_len(rpc_item, offset - offset_old);
1000 /* create here the program specific sub-tree */
1002 pitem = proto_tree_add_item(tree, proto, offset, END_OF_FRAME);
1004 ptree = proto_item_add_subtree(pitem, ett);
1007 /* call a specific dissection */
1008 if (dissect_function != NULL) {
1009 offset = dissect_function(pd, offset, fd, ptree);
1012 /* dissect any remaining bytes (incomplete dissection) as pure data in
1014 dissect_data(pd, offset, fd, ptree);
1019 /* will be called from file.c on every new file open */
1021 rpc_init_protocol(void)
1024 rpc_call_firstfree = 0;
1028 /* will be called once from register.c at startup time */
1030 proto_register_rpc(void)
1032 proto_rpc = proto_register_protocol("Remote Procedure Call", "rpc");
1034 /* please remove this, if all specific dissectors are ready */
1035 init_incomplete_dissect();