2 * Routines for rpc dissection
3 * Copyright 1999, Uwe Girlich <Uwe.Girlich@philosys.de>
5 * $Id: packet-rpc.c,v 1.5 1999/11/10 15:10:32 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 BOOT_PROGRAM 100026
210 #define MNT_PROGRAM 100005
211 #define NLM_PROGRAM 100021
212 #define PMAP_PROGRAM 100000
213 #define STAT_PROGRAM 100024
214 #define YPBIND_PROGRAM 100007
215 #define YPSERV_PROGRAM 100004
216 #define YPXFR_PROGRAM 100069
218 static int proto_boot = -1;
219 static int proto_mnt = -1;
220 static int proto_nlm = -1;
221 static int proto_pmap = -1;
222 static int proto_stat = -1;
223 static int proto_ypbind = -1;
224 static int proto_ypserv = -1;
225 static int proto_ypxfr = -1;
227 void init_incomplete_dissect(void)
229 proto_boot = proto_register_protocol("Bootparameters", "BOOT");
230 rpc_init_prog(proto_boot, BOOT_PROGRAM, ETT_BOOT);
232 proto_mnt = proto_register_protocol("Mount", "MNT");
233 rpc_init_prog(proto_mnt, MNT_PROGRAM, ETT_MNT);
235 proto_nlm = proto_register_protocol("Network Lock Manager", "NLM");
236 rpc_init_prog(proto_nlm, NLM_PROGRAM, ETT_NLM);
238 proto_pmap = proto_register_protocol("Portmapper", "PMAP");
239 rpc_init_prog(proto_pmap, PMAP_PROGRAM, ETT_PMAP);
241 proto_stat = proto_register_protocol("Status", "STAT");
242 rpc_init_prog(proto_stat, STAT_PROGRAM, ETT_STAT);
244 proto_ypbind = proto_register_protocol("Yellow Page Bind", "YPBIND");
245 rpc_init_prog(proto_ypbind, YPBIND_PROGRAM, ETT_YPBIND);
247 proto_ypserv = proto_register_protocol("Yellow Page Server", "YPSERV");
248 rpc_init_prog(proto_ypserv, YPSERV_PROGRAM, ETT_YPSERV);
250 proto_ypxfr = proto_register_protocol("Yellow Page Transfer", "YPXFR");
251 rpc_init_prog(proto_ypxfr, YPXFR_PROGRAM, ETT_YPXFR);
256 * Init the hash tables. It will be called from ethereal_proto_init().
257 * ethereal_proto_init() calls later proto_init(), which calls
258 * register_all_protocols().
259 * The proto_register_<some rpc program> functions use these hash tables
260 * here, so we need this order!
265 rpc_progs = g_hash_table_new(rpc_prog_hash, rpc_prog_equal);
266 rpc_procs = g_hash_table_new(rpc_proc_hash, rpc_proc_equal);
270 /* static array, first quick implementation, I'll switch over to GList soon */
271 rpc_call_info rpc_call_table[RPC_CALL_TABLE_LENGTH];
272 guint32 rpc_call_index = 0;
273 guint32 rpc_call_firstfree = 0;
276 rpc_call_insert(rpc_call_info *call)
278 /* some space left? */
279 if (rpc_call_firstfree<RPC_CALL_TABLE_LENGTH) {
280 /* some space left */
281 /* take the first free entry */
282 rpc_call_index = rpc_call_firstfree;
283 /* increase this limit */
284 rpc_call_firstfree++;
285 /* rpc_call_firstfree may now be RPC_CALL_TABLE_LENGTH */
289 /* the next entry, with wrap around */
290 rpc_call_index = (rpc_call_index+1) % rpc_call_firstfree;
293 /* put the entry in */
294 memcpy(&rpc_call_table[rpc_call_index],call,sizeof(*call));
300 rpc_call_lookup(rpc_call_info *call)
307 rpc_call_table[i].xid == call->xid &&
308 rpc_call_table[i].conversation == call->conversation
310 return &rpc_call_table[i];
312 if (rpc_call_firstfree) {
313 /* decrement by one, go to rpc_call_firstfree-1
314 at the start of the list */
315 i = (i-1+rpc_call_firstfree) % rpc_call_firstfree;
317 } while (i!=rpc_call_index);
323 roundup(unsigned int a)
325 unsigned int mod = a % 4;
326 return a + ((mod)? 4-mod : 0);
331 dissect_rpc_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
332 char* name, char* type)
336 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
337 value = EXTRACT_UINT(pd, offset+0);
340 proto_tree_add_text(tree, offset, 4,
341 "%s (%s): %u", name, type, value);
350 dissect_rpc_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
351 char* name, char* type)
356 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
357 value_high = EXTRACT_UINT(pd, offset+0);
358 value_low = EXTRACT_UINT(pd, offset+4);
362 proto_tree_add_text(tree, offset, 8,
363 "%s (%s): %x%08x", name, type, value_high, value_low);
365 proto_tree_add_text(tree, offset, 8,
366 "%s (%s): %u", name, type, value_low);
375 /* arbitrary limit */
376 #define RPC_STRING_MAXBUF 1024
379 dissect_rpc_string(const u_char *pd, int offset, frame_data *fd, proto_tree *tree, char* name)
381 proto_item *string_item;
382 proto_tree *string_tree = NULL;
384 guint32 string_length;
386 guint32 string_length_full;
387 char string_buffer[RPC_STRING_MAXBUF];
389 if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
390 string_length = EXTRACT_UINT(pd,offset+0);
391 string_length_full = roundup(string_length);
392 string_fill = string_length_full - string_length;
393 if (!BYTES_ARE_IN_FRAME(offset+4,string_length_full)) return offset;
394 if (string_length>=sizeof(string_buffer)) return offset;
395 memcpy(string_buffer,pd+offset+4,string_length);
396 string_buffer[string_length] = '\0';
398 string_item = proto_tree_add_text(tree,offset+0,
399 4+string_length_full,
400 "%s: %s", name, string_buffer);
402 string_tree = proto_item_add_subtree(string_item, ETT_RPC_STRING);
406 proto_tree_add_text(string_tree,offset+0,4,
407 "length: %u", string_length);
408 proto_tree_add_text(string_tree,offset+4,string_length,
409 "text: %s", string_buffer);
411 proto_tree_add_text(string_tree,offset+4+string_length,string_fill,
412 "fill bytes: opaque data");
415 offset += 4 + string_length_full;
421 dissect_rpc_auth( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
427 /* both checks are made outside */
428 /* if (!BYTES_ARE_IN_FRAME(offset,8)) return; */
429 flavor = EXTRACT_UINT(pd,offset+0);
430 length = EXTRACT_UINT(pd,offset+4);
431 length_full = roundup(length);
432 /* if (!BYTES_ARE_IN_FRAME(offset+8,full_length)) return; */
435 proto_tree_add_text(tree,offset+0,4,
436 "Flavor: %s (%u)", val_to_str(flavor,rpc_auth_flavor,"Unknown"),flavor);
437 proto_tree_add_text(tree,offset+4,4,
438 "Length: %u", length);
452 proto_tree *gtree = NULL;
454 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
455 stamp = EXTRACT_UINT(pd,offset+0);
457 proto_tree_add_text(tree,offset+0,4,
458 "stamp: 0x%08x", stamp);
461 offset = dissect_rpc_string(pd,offset,fd,tree,"machinename");
463 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
464 uid = EXTRACT_UINT(pd,offset+0);
466 proto_tree_add_text(tree,offset+0,4,
470 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
471 gid = EXTRACT_UINT(pd,offset+0);
473 proto_tree_add_text(tree,offset+0,4,
477 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
478 gids_count = EXTRACT_UINT(pd,offset+0);
480 gitem = proto_tree_add_text(tree, offset, 4+gids_count*4,
482 gtree = proto_item_add_subtree(gitem, ETT_RPC_GIDS);
485 if (!BYTES_ARE_IN_FRAME(offset,4*gids_count)) return;
486 for (gids_i = 0 ; gids_i < gids_count ; gids_i++) {
487 gids_entry = EXTRACT_UINT(pd,offset+0);
489 proto_tree_add_text(gtree, offset, 4,
493 /* how can I NOW change the gitem to print a list with
494 the first 16 gids? */
502 /* I have no tcpdump file with such a packet to verify the
503 info from the RFC 1050 */
512 proto_tree_add_text(tree,offset,
513 length_full, "opaque data");
519 dissect_rpc_cred( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
526 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
527 length = EXTRACT_UINT(pd,offset+4);
528 length_full = roundup(length);
529 if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
532 citem = proto_tree_add_text(tree, offset, 8+length_full,
534 ctree = proto_item_add_subtree(citem, ETT_RPC_CRED);
535 dissect_rpc_auth(pd, offset, fd, ctree);
537 offset += 8 + length_full;
544 dissect_rpc_verf( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
547 unsigned int length_full;
551 if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
552 length = EXTRACT_UINT(pd,offset+4);
553 length_full = roundup(length);
554 if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
557 vitem = proto_tree_add_text(tree, offset, 8+length_full,
559 vtree = proto_item_add_subtree(vitem, ETT_RPC_VERF);
560 dissect_rpc_auth(pd, offset, fd, vtree);
562 offset += 8 + length_full;
569 dissect_rpc( const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
570 guint32 msg_type, void* info)
573 unsigned int rpcvers;
575 unsigned int vers = 0;
576 unsigned int proc = 0;
580 unsigned int reply_state;
581 unsigned int accept_state;
582 unsigned int reject_state;
584 char *msg_type_name = NULL;
586 char *procname = NULL;
587 static char procname_static[20];
589 unsigned int vers_low;
590 unsigned int vers_high;
592 unsigned int auth_state;
594 proto_item *rpc_item=NULL;
595 proto_tree *rpc_tree = NULL;
597 proto_item *pitem=NULL;
598 proto_tree *ptree = NULL;
599 int offset_old = offset;
601 rpc_call_info rpc_call_msg;
602 rpc_proc_info_key key;
603 rpc_proc_info_value *value = NULL;
604 conversation_t* conversation;
606 /* the last parameter can be either of these two types */
607 rpc_call_info *rpc_call;
608 rpc_prog_info_key rpc_prog_key;
609 rpc_prog_info_value *rpc_prog;
611 dissect_function_t *dissect_function = NULL;
613 if (check_col(fd, COL_PROTOCOL))
614 col_add_str(fd, COL_PROTOCOL, "RPC");
617 rpc_item = proto_tree_add_item(tree, proto_rpc, offset, END_OF_FRAME, NULL);
619 rpc_tree = proto_item_add_subtree(rpc_item, ETT_RPC);
623 xid = EXTRACT_UINT(pd,offset+0);
625 proto_tree_add_text(rpc_tree,offset+0,4,
626 "XID: 0x%x (%u)", xid, xid);
629 /* we should better compare this with the argument?! */
630 msg_type = EXTRACT_UINT(pd,offset+4);
631 msg_type_name = val_to_str(msg_type,rpc_msg_type,"%u");
633 proto_tree_add_text(rpc_tree,offset+4,4,
635 msg_type_name, msg_type);
640 if (msg_type==RPC_CALL) {
641 /* we know already the proto-entry and the ETT-const */
642 rpc_prog = (rpc_prog_info_value*)info;
643 proto = rpc_prog->proto;
645 progname = rpc_prog->progname;
647 rpcvers = EXTRACT_UINT(pd,offset+0);
649 proto_tree_add_text(rpc_tree,offset+0,4,
650 "RPC Version: %u", rpcvers);
653 prog = EXTRACT_UINT(pd,offset+4);
656 proto_tree_add_text(rpc_tree,offset+4,4,
657 "Program: %s (%u)", progname, prog);
660 if (check_col(fd, COL_PROTOCOL)) {
661 /* Set the protocol name to the underlying
663 col_add_fstr(fd, COL_PROTOCOL, "%s", progname);
666 if (!BYTES_ARE_IN_FRAME(offset+8,4)) return;
667 vers = EXTRACT_UINT(pd,offset+8);
669 proto_tree_add_text(rpc_tree,offset+8,4,
670 "Program Version: %u",vers);
673 if (!BYTES_ARE_IN_FRAME(offset+12,4)) return;
674 proc = EXTRACT_UINT(pd,offset+12);
680 value = g_hash_table_lookup(rpc_procs,&key);
682 dissect_function = value->dissect_call;
683 procname = value->name;
686 /* happens only with strange program versions or
687 non-existing dissectors */
688 dissect_function = NULL;
689 sprintf(procname_static, "proc-%u", proc);
690 procname = procname_static;
693 proto_tree_add_text(rpc_tree,offset+12,4,
694 "Procedure: %s (%u)", procname, proc);
697 if (check_col(fd, COL_INFO)) {
698 col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
705 conversation = find_conversation(&pi.src, &pi.dst, pi.ptype,
706 pi.srcport, pi.destport);
707 if (conversation == NULL) {
708 /* It's not part of any conversation - create a new one. */
709 conversation = conversation_new(&pi.src, &pi.dst, pi.ptype,
710 pi.srcport, pi.destport, NULL);
713 /* prepare the key data */
714 rpc_call_msg.xid = xid;
715 rpc_call_msg.conversation = conversation;
717 /* look up the request */
718 if (rpc_call_lookup(&rpc_call_msg)) {
719 /* duplicate request */
720 if (check_col(fd, COL_INFO)) {
721 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
725 /* prepare the value data */
726 rpc_call_msg.replies = 0;
727 rpc_call_msg.prog = prog;
728 rpc_call_msg.vers = vers;
729 rpc_call_msg.proc = proc;
730 rpc_call_msg.proc_info = value;
732 rpc_call_insert(&rpc_call_msg);
737 offset = dissect_rpc_cred(pd, offset, fd, rpc_tree);
738 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
740 /* go to the next dissector */
741 /* goto dissect_rpc_prog; */
743 } /* end of RPC call */
744 else if (msg_type == RPC_REPLY)
746 /* we know already the type from the calling routine */
747 rpc_call = (rpc_call_info*)info;
748 prog = rpc_call->prog;
749 vers = rpc_call->vers;
750 proc = rpc_call->proc;
751 if (rpc_call->proc_info != NULL) {
752 dissect_function = rpc_call->proc_info->dissect_reply;
753 if (rpc_call->proc_info->name != NULL) {
754 procname = rpc_call->proc_info->name;
757 sprintf(procname_static, "proc-%u", proc);
758 procname = procname_static;
762 dissect_function = NULL;
763 sprintf(procname_static, "proc-%u", proc);
764 procname = procname_static;
768 rpc_prog_key.prog = prog;
769 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
772 progname = "Unknown";
775 proto = rpc_prog->proto;
777 progname = rpc_prog->progname;
779 if (check_col(fd, COL_PROTOCOL)) {
780 /* Set the protocol name to the underlying
782 col_add_fstr(fd, COL_PROTOCOL, "%s",
787 if (check_col(fd, COL_INFO)) {
788 col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
796 proto_tree_add_text(rpc_tree,0,0,
799 proto_tree_add_text(rpc_tree,0,0,
800 "Program Version: %u", vers);
801 proto_tree_add_text(rpc_tree,0,0,
802 "Procedure: %s (%u)", procname, proc);
805 if (rpc_call->replies>1) {
806 if (check_col(fd, COL_INFO)) {
807 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
811 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
812 reply_state = EXTRACT_UINT(pd,offset+0);
814 proto_tree_add_text(rpc_tree,offset+0, 4,
815 "Reply State: %s (%u)",
816 val_to_str(reply_state,rpc_reply_state,"Unknown"),
821 if (reply_state == MSG_ACCEPTED) {
822 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
823 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
824 accept_state = EXTRACT_UINT(pd,offset+0);
826 proto_tree_add_text(rpc_tree,offset+0, 4,
827 "Accept State: %s (%u)",
828 val_to_str(accept_state,rpc_accept_state,"Unknown"),
832 switch (accept_state) {
834 /* now goto the lower protocol */
835 goto dissect_rpc_prog;
838 if (!BYTES_ARE_IN_FRAME(offset,8)) return;
839 vers_low = EXTRACT_UINT(pd,offset+0);
840 vers_high = EXTRACT_UINT(pd,offset+4);
842 proto_tree_add_text(rpc_tree,
844 "min. Program Version: %u",
846 proto_tree_add_text(rpc_tree,
848 "max. Program Version: %u",
857 } else if (reply_state == MSG_DENIED) {
858 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
859 reject_state = EXTRACT_UINT(pd,offset+0);
861 proto_tree_add_text(rpc_tree, offset+0, 4,
862 "Reject State: %s (%u)",
863 val_to_str(reject_state,rpc_reject_state,"Unknown"),
868 if (reject_state==RPC_MISMATCH) {
869 if (!BYTES_ARE_IN_FRAME(offset,8)) return;
870 vers_low = EXTRACT_UINT(pd,offset+0);
871 vers_high = EXTRACT_UINT(pd,offset+4);
873 proto_tree_add_text(rpc_tree,
875 "min. RPC Version: %u",
877 proto_tree_add_text(rpc_tree,
879 "max. RPC Version: %u",
883 } else if (reject_state==AUTH_ERROR) {
884 if (!BYTES_ARE_IN_FRAME(offset,4)) return;
885 auth_state = EXTRACT_UINT(pd,offset+0);
887 proto_tree_add_text(rpc_tree,
889 "Authentication error: %s (%u)",
890 val_to_str(auth_state,rpc_auth_state,"Unknown"),
896 } /* end of RPC reply */
899 /* I know, goto is evil but it works as it is. */
901 /* now we know, that RPC was shorter */
903 proto_item_set_len(rpc_item, offset - offset_old);
906 /* create here the program specific sub-tree */
908 pitem = proto_tree_add_item(tree, proto, offset, END_OF_FRAME);
910 ptree = proto_item_add_subtree(pitem, ett);
913 /* call a specific dissection */
914 if (dissect_function != NULL) {
915 offset = dissect_function(pd, offset, fd, ptree);
918 /* dissect any remaining bytes (incomplete dissection) as pure data in
920 dissect_data(pd, offset, fd, ptree);
923 /* will be called from file.c on every new file open */
925 rpc_init_protocol(void)
928 rpc_call_firstfree = 0;
932 /* will be called once from register.c at startup time */
934 proto_register_rpc(void)
936 proto_rpc = proto_register_protocol("Remote Procedure Call", "rpc");
938 /* please remove this, if all specific dissectors are ready */
939 init_incomplete_dissect();