Move calls to "dissector_add()" out of the register routines for TCP and
[obnox/wireshark/wip.git] / packet-rpc.c
1 /* packet-rpc.c
2  * Routines for rpc dissection
3  * Copyright 1999, Uwe Girlich <Uwe.Girlich@philosys.de>
4  * 
5  * $Id: packet-rpc.c,v 1.29 2000/04/04 06:46:27 guy Exp $
6  * 
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
9  * Copyright 1998 Gerald Combs
10  * 
11  * Copied from packet-smb.c
12  * 
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.
17  * 
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.
22  * 
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.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #ifdef HAVE_SYS_TYPES_H
33 # include <sys/types.h>
34 #endif
35
36 #include <glib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include "packet.h"
41 #include "conversation.h"
42 #include "packet-rpc.h"
43
44
45 #define RPC_RM_FRAGLEN  0x7fffffffL
46
47 static struct true_false_string yesno = { "Yes", "No" };
48
49
50 static const value_string rpc_msg_type[3] = {
51         { RPC_CALL, "Call" },
52         { RPC_REPLY, "Reply" },
53         { 0, NULL }
54 };
55
56 static const value_string rpc_reply_state[3] = {
57         { MSG_ACCEPTED, "accepted" },
58         { MSG_DENIED, "denied" },
59         { 0, NULL }
60 };
61
62 const value_string rpc_auth_flavor[] = {
63         { AUTH_NULL, "AUTH_NULL" },
64         { AUTH_UNIX, "AUTH_UNIX" },
65         { AUTH_SHORT, "AUTH_SHORT" },
66         { AUTH_DES, "AUTH_DES" },
67         { 0, NULL }
68 };
69
70 static const value_string rpc_accept_state[6] = {
71         { SUCCESS, "RPC executed successfully" },
72         { PROG_UNAVAIL, "remote hasn't exported program" },
73         { PROG_MISMATCH, "remote can't support version #" },
74         { PROC_UNAVAIL, "program can't support procedure" },
75         { GARBAGE_ARGS, "procedure can't decode params" },
76         { 0, NULL }
77 };
78
79 static const value_string rpc_reject_state[3] = {
80         { RPC_MISMATCH, "RPC_MISMATCH" },
81         { AUTH_ERROR, "AUTH_ERROR" },
82         { 0, NULL }
83 };
84
85 static const value_string rpc_auth_state[6] = {
86         { AUTH_BADCRED, "bad credential (seal broken)" },
87         { AUTH_REJECTEDCRED, "client must begin new session" },
88         { AUTH_BADVERF, "bad verifier (seal broken)" },
89         { AUTH_REJECTEDVERF, "verifier expired or replayed" },
90         { AUTH_TOOWEAK, "rejected for security reasons" },
91         { 0, NULL }
92 };
93
94
95 /* the protocol number */
96 static int proto_rpc = -1;
97 static int hf_rpc_lastfrag = -1;
98 static int hf_rpc_fraglen = -1;
99 static int hf_rpc_xid = -1;
100 static int hf_rpc_msgtype = -1;
101 static int hf_rpc_version = -1;
102 static int hf_rpc_version_min = -1;
103 static int hf_rpc_version_max = -1;
104 static int hf_rpc_program = -1;
105 static int hf_rpc_programversion = -1;
106 static int hf_rpc_programversion_min = -1;
107 static int hf_rpc_programversion_max = -1;
108 static int hf_rpc_procedure = -1;
109 static int hf_rpc_auth_flavor = -1;
110 static int hf_rpc_auth_length = -1;
111 static int hf_rpc_auth_machinename = -1;
112 static int hf_rpc_auth_stamp = -1;
113 static int hf_rpc_auth_uid = -1;
114 static int hf_rpc_auth_gid = -1;
115 static int hf_rpc_state_accept = -1;
116 static int hf_rpc_state_reply = -1;
117 static int hf_rpc_state_reject = -1;
118 static int hf_rpc_state_auth = -1;
119 static int hf_rpc_dup = -1;
120 static int hf_rpc_call_dup = -1;
121 static int hf_rpc_reply_dup = -1;
122 static int hf_rpc_value_follows = -1;
123
124 static gint ett_rpc = -1;
125 static gint ett_rpc_string = -1;
126 static gint ett_rpc_cred = -1;
127 static gint ett_rpc_verf = -1;
128 static gint ett_rpc_gids = -1;
129
130 /* Hash table with info on RPC program numbers */
131 static GHashTable *rpc_progs;
132
133 /* Hash table with info on RPC procedure numbers */
134 static GHashTable *rpc_procs;
135
136
137 /***********************************/
138 /* Hash array with procedure names */
139 /***********************************/
140
141 /* compare 2 keys */
142 gint
143 rpc_proc_equal(gconstpointer k1, gconstpointer k2)
144 {
145         rpc_proc_info_key* key1 = (rpc_proc_info_key*) k1;
146         rpc_proc_info_key* key2 = (rpc_proc_info_key*) k2;
147
148         return ((key1->prog == key2->prog && 
149                 key1->vers == key2->vers &&
150                 key1->proc == key2->proc) ?
151         TRUE : FALSE);
152 }
153
154 /* calculate a hash key */
155 guint
156 rpc_proc_hash(gconstpointer k)
157 {
158         rpc_proc_info_key* key = (rpc_proc_info_key*) k;
159
160         return (key->prog ^ (key->vers<<16) ^ (key->proc<<24));
161 }
162
163
164 /* insert some entries */
165 void
166 rpc_init_proc_table(guint prog, guint vers, const vsff *proc_table)
167 {
168         const vsff *proc;
169
170         for (proc = proc_table ; proc->strptr!=NULL; proc++) {
171                 rpc_proc_info_key *key;
172                 rpc_proc_info_value *value;
173
174                 key = (rpc_proc_info_key *) g_malloc(sizeof(rpc_proc_info_key));
175                 key->prog = prog;
176                 key->vers = vers;
177                 key->proc = proc->value;
178
179                 value = (rpc_proc_info_value *) g_malloc(sizeof(rpc_proc_info_value));
180                 value->name = proc->strptr;
181                 value->dissect_call = proc->dissect_call;
182                 value->dissect_reply = proc->dissect_reply;
183
184                 g_hash_table_insert(rpc_procs,key,value);
185         }
186 }
187
188 /*----------------------------------------*/
189 /* end of Hash array with procedure names */
190 /*----------------------------------------*/
191
192
193 /*********************************/
194 /* Hash array with program names */
195 /*********************************/
196
197 /* compare 2 keys */
198 gint
199 rpc_prog_equal(gconstpointer k1, gconstpointer k2)
200 {
201         rpc_prog_info_key* key1 = (rpc_prog_info_key*) k1;
202         rpc_prog_info_key* key2 = (rpc_prog_info_key*) k2;
203
204         return ((key1->prog == key2->prog) ?
205         TRUE : FALSE);
206 }
207
208
209 /* calculate a hash key */
210 guint
211 rpc_prog_hash(gconstpointer k)
212 {
213         rpc_prog_info_key* key = (rpc_prog_info_key*) k;
214
215         return (key->prog);
216 }
217
218
219 void
220 rpc_init_prog(int proto, guint32 prog, int ett)
221 {
222         rpc_prog_info_key *key;
223         rpc_prog_info_value *value;
224         char *uc_progname = NULL, *lc_progname = NULL;
225
226         key = (rpc_prog_info_key *) g_malloc(sizeof(rpc_prog_info_key));
227         key->prog = prog;
228
229         value = (rpc_prog_info_value *) g_malloc(sizeof(rpc_prog_info_value));
230         value->proto = proto;
231         value->ett = ett;
232
233         lc_progname = proto_registrar_get_abbrev(proto);
234         if ( lc_progname )
235         {
236                 int i;
237                 uc_progname = strdup(lc_progname);
238                 for (i=0; i<strlen(uc_progname); i++)
239                 {
240                         uc_progname[i] = toupper(uc_progname[i]);
241                 }
242         }
243         value->progname = uc_progname;
244
245         g_hash_table_insert(rpc_progs,key,value);
246 }
247
248 /*      return the name associated with a previously registered program. This
249         should probably eventually be expanded to use the rpc YP/NIS map
250         so that it can give names for programs not handled by ethereal */
251 char *rpc_prog_name(guint32 prog)
252 {
253         char *progname = NULL;
254         rpc_prog_info_key       rpc_prog_key;
255         rpc_prog_info_value     *rpc_prog;
256
257         rpc_prog_key.prog = prog;
258         if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
259                 progname = "Unknown";
260         }
261         else {
262                 progname = rpc_prog->progname;
263         }
264         return progname;
265 }
266
267
268 /*--------------------------------------*/
269 /* end of Hash array with program names */
270 /*--------------------------------------*/
271
272 /* static array, first quick implementation, I'll switch over to GList soon */ 
273 rpc_call_info rpc_call_table[RPC_CALL_TABLE_LENGTH];
274 guint32 rpc_call_index = 0;
275 guint32 rpc_call_firstfree = 0;
276
277 void
278 rpc_call_insert(rpc_call_info *call)
279 {
280         /* some space left? */
281         if (rpc_call_firstfree<RPC_CALL_TABLE_LENGTH) {
282                 /* some space left */
283                 /* take the first free entry */
284                 rpc_call_index = rpc_call_firstfree;
285                 /* increase this limit */
286                 rpc_call_firstfree++;
287                 /* rpc_call_firstfree may now be RPC_CALL_TABLE_LENGTH */
288         }
289         else {
290                 /* no space left */
291                 /* the next entry, with wrap around */
292                 rpc_call_index = (rpc_call_index+1) % rpc_call_firstfree;
293         }
294                 
295         /* put the entry in */
296         memcpy(&rpc_call_table[rpc_call_index],call,sizeof(*call));
297         return;
298 }
299
300
301 rpc_call_info*
302 rpc_call_lookup(rpc_call_info *call)
303 {
304         int i;
305
306         i = rpc_call_index;
307         do {
308                 if (
309                         rpc_call_table[i].xid == call->xid &&
310                         rpc_call_table[i].conversation == call->conversation
311                 ) {
312                         return &rpc_call_table[i];
313                 }
314                 if (rpc_call_firstfree) {
315                         /* decrement by one, go to rpc_call_firstfree-1 
316                            at the start of the list */
317                         i = (i-1+rpc_call_firstfree) % rpc_call_firstfree;
318                 }
319         } while (i!=rpc_call_index);
320         return NULL;
321 }
322
323
324 unsigned int
325 rpc_roundup(unsigned int a)
326 {
327         unsigned int mod = a % 4;
328         return a + ((mod)? 4-mod : 0);
329 }
330
331
332 int
333 dissect_rpc_bool(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
334 int hfindex)
335 {
336         guint32 value;
337
338         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
339         value = EXTRACT_UINT(pd, offset+0);
340         if (tree)
341                 proto_tree_add_item(tree, hfindex, offset, 4, value);
342         offset += 4;
343
344         return offset;
345 }
346
347
348 int
349 dissect_rpc_uint32(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
350 char* name, char* type)
351 {
352         guint32 value;
353
354         if (!BYTES_ARE_IN_FRAME(offset,4)) return offset;
355         value = EXTRACT_UINT(pd, offset+0);
356
357         if (tree) {
358                 proto_tree_add_text(tree, offset, 4,
359                 "%s: %u", name, value);
360         }
361
362         offset += 4;
363         return offset;
364 }
365
366
367 int
368 dissect_rpc_uint64(const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
369 char* name, char* type)
370 {
371         guint32 value_low;
372         guint32 value_high;
373
374         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
375         value_high = EXTRACT_UINT(pd, offset+0);
376         value_low = EXTRACT_UINT(pd, offset+4);
377
378         if (tree) {
379                 if (value_high)
380                         proto_tree_add_text(tree, offset, 8,
381                                 "%s: 0x%x%08x", name, value_high, value_low);
382                 else
383                         proto_tree_add_text(tree, offset, 8,
384                                 "%s: %u", name, value_low);
385         }
386
387         offset += 8;
388         return offset;
389 }
390
391
392 static int
393 dissect_rpc_opaque_data(const u_char *pd, int offset, frame_data *fd,
394     proto_tree *tree, int hfindex, gboolean string_data,
395     char **string_buffer_ret)
396 {
397         proto_item *string_item = NULL;
398         proto_tree *string_tree = NULL;
399         int old_offset = offset;
400
401         int length_truncated = 0;
402
403         int string_truncated = 0;
404         guint32 string_length = 0;
405         guint32 string_length_full;
406         guint32 string_length_packet;
407         guint32 string_length_copy = 0;
408
409         int fill_truncated = 0;
410         guint32 fill_length  = 0;
411         guint32 fill_length_packet  = 0;
412         guint32 fill_length_copy  = 0;
413
414         char *string_buffer = NULL;
415         char *string_buffer_print = NULL;
416
417         if (BYTES_ARE_IN_FRAME(offset,4)) {
418                 string_length = EXTRACT_UINT(pd,offset+0);
419                 string_length_full = rpc_roundup(string_length);
420                 string_length_packet = pi.captured_len - (offset + 4);
421                 if (string_length_packet < string_length) {
422                         /* truncated string */
423                         string_truncated = 1;
424                         string_length_copy = string_length_packet;
425                         fill_truncated = 2;
426                         fill_length = 0;
427                         fill_length_packet = 0;
428                         fill_length_copy = 0;
429                 }
430                 else {
431                         /* full string data */
432                         string_truncated = 0;
433                         string_length_copy = string_length;
434                         fill_length = string_length_full - string_length;
435                         fill_length_packet = pi.captured_len - (offset + 4 + string_length);
436                         if (fill_length_packet < fill_length) {
437                                 /* truncated fill bytes */
438                                 fill_length_copy = fill_length_packet;
439                                 fill_truncated = 1;
440                         }
441                         else {
442                                 /* full fill bytes */
443                                 fill_length_copy = fill_length;
444                                 fill_truncated = 0;
445                         }
446                 }
447                 string_buffer = (char*)g_malloc(string_length_copy + 
448                         (string_data ? 1 : 0));
449                 memcpy(string_buffer,pd+offset+4,string_length_copy);
450                 if (string_data)
451                         string_buffer[string_length_copy] = '\0';
452
453                 /* calculate a nice printable string */
454                 if (string_length) {
455                         if (string_length != string_length_copy) {
456                                 if (string_data) {
457                                         /* alloc maximum data area */
458                                         string_buffer_print = (char*)g_malloc(string_length_copy + 12 + 1);
459                                         /* copy over the data */
460                                         memcpy(string_buffer_print,string_buffer,string_length_copy);
461                                         /* append a 0 byte for sure printing */
462                                         string_buffer_print[string_length_copy] = '\0';
463                                         /* append <TRUNCATED> */
464                                         /* This way, we get the TRUNCATED even
465                                            in the case of totally wrong packets,
466                                            where \0 are inside the string.
467                                            TRUNCATED will appear at the
468                                            first \0 or at the end (where we 
469                                            put the securing \0).
470                                         */
471                                         strcat(string_buffer_print,"<TRUNCATED>");
472                                 }
473                                 else {
474                                         string_buffer_print = g_strdup("<DATA><TRUNCATED>");
475                                 }
476                         }
477                         else {
478                                 if (string_data) {
479                                         string_buffer_print = g_strdup(string_buffer);
480                                 }
481                                 else {
482                                         string_buffer_print = g_strdup("<DATA>");
483                                 }
484                         }
485                 }
486                 else {
487                         string_buffer_print = g_strdup("<EMPTY>");
488                 }
489         }
490         else {
491                 length_truncated = 1;
492                 string_truncated = 2;
493                 fill_truncated = 2;
494                 string_buffer = g_strdup("");
495                 string_buffer_print = g_strdup("<TRUNCATED>");
496         }
497
498         if (tree) {
499                 string_item = proto_tree_add_text(tree,offset+0, END_OF_FRAME,
500                         "%s: %s", proto_registrar_get_name(hfindex), string_buffer_print);
501                 if (string_data) {
502                         proto_tree_add_item_hidden(tree, hfindex, offset+4,
503                                 string_length_copy, string_buffer);
504                 }
505                 if (string_item) {
506                         string_tree = proto_item_add_subtree(string_item, ett_rpc_string);
507                 }
508         }
509         if (length_truncated) {
510                 if (string_tree)
511                         proto_tree_add_text(string_tree,
512                                 offset,pi.captured_len-offset,
513                                 "length: <TRUNCATED>");
514                 offset = pi.captured_len;
515         } else {
516                 if (string_tree)
517                         proto_tree_add_text(string_tree,offset+0,4,
518                                 "length: %u", string_length);
519                 offset += 4;
520
521                 if (string_tree)
522                         proto_tree_add_text(string_tree,offset,string_length_copy,
523                                 "contents: %s", string_buffer_print);
524                 offset += string_length_copy;
525                 if (fill_length) {
526                         if (string_tree) {
527                                 if (fill_truncated) {
528                                         proto_tree_add_text(string_tree,
529                                         offset,fill_length_copy,
530                                         "fill bytes: opaque data<TRUNCATED>");
531                                 }
532                                 else {
533                                         proto_tree_add_text(string_tree,
534                                         offset,fill_length_copy,
535                                         "fill bytes: opaque data");
536                                 }
537                         }
538                         offset += fill_length_copy;
539                 }
540         }
541         
542         if (string_item) {
543                 proto_item_set_len(string_item, offset - old_offset);
544         }
545
546         if (string_buffer       != NULL) g_free (string_buffer      );
547         if (string_buffer_print != NULL) {
548                 if (string_buffer_ret != NULL)
549                         *string_buffer_ret = string_buffer_print;
550                 else
551                         g_free (string_buffer_print);
552         }
553         return offset;
554 }
555
556
557 int
558 dissect_rpc_string(const u_char *pd, int offset, frame_data *fd,
559     proto_tree *tree, int hfindex, char **string_buffer_ret)
560 {
561         offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, TRUE,
562             string_buffer_ret);
563
564         return offset;
565 }
566
567
568 int
569 dissect_rpc_data(const u_char *pd, int offset, frame_data *fd,
570     proto_tree *tree, int hfindex)
571 {
572         offset = dissect_rpc_opaque_data(pd, offset, fd, tree, hfindex, FALSE,
573             NULL);
574
575         return offset;
576 }
577
578
579 int
580 dissect_rpc_list(const u_char *pd, int offset, frame_data *fd,
581         proto_tree *tree, dissect_function_t *rpc_list_dissector)
582 {
583         guint32 value_follows;
584
585         while (1) {
586                 if (!BYTES_ARE_IN_FRAME(offset,4)) break;
587                 value_follows = EXTRACT_UINT(pd, offset+0);
588                 proto_tree_add_item(tree,hf_rpc_value_follows,
589                         offset+0, 4, value_follows);
590                 offset += 4;
591                 if (value_follows == 1) {
592                         offset = rpc_list_dissector(pd, offset, fd, tree);
593                 }
594                 else {
595                         break;
596                 }
597         }
598
599         return offset;
600 }
601
602
603 void
604 dissect_rpc_auth( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
605 {
606         guint flavor;
607         guint length;
608         guint length_full;
609
610         /* both checks are made outside */
611         /* if (!BYTES_ARE_IN_FRAME(offset,8)) return; */
612         flavor = EXTRACT_UINT(pd,offset+0);
613         length = EXTRACT_UINT(pd,offset+4);
614         length_full = rpc_roundup(length);
615         /* if (!BYTES_ARE_IN_FRAME(offset+8,full_length)) return; */
616
617         if (tree) {
618                 proto_tree_add_item(tree, hf_rpc_auth_flavor, offset+0, 4,
619                         flavor);
620                 proto_tree_add_item(tree, hf_rpc_auth_length, offset+4, 4,
621                         length);
622         }
623
624         offset += 8;
625
626         switch (flavor) {
627                 case AUTH_UNIX: {
628                         guint stamp;
629                         guint uid;
630                         guint gid;
631                         guint gids_count;
632                         guint gids_i;
633                         guint gids_entry;
634                         proto_item *gitem;
635                         proto_tree *gtree = NULL;
636
637                         if (!BYTES_ARE_IN_FRAME(offset,4)) return;
638                         stamp = EXTRACT_UINT(pd,offset+0);
639                         if (tree)
640                                 proto_tree_add_item(tree, hf_rpc_auth_stamp,
641                                         offset+0, 4, stamp);
642                         offset += 4;
643
644                         offset = dissect_rpc_string(pd,offset,fd,
645                                 tree,hf_rpc_auth_machinename,NULL);
646
647                         if (!BYTES_ARE_IN_FRAME(offset,4)) return;
648                         uid = EXTRACT_UINT(pd,offset+0);
649                         if (tree)
650                                 proto_tree_add_item(tree, hf_rpc_auth_uid,
651                                         offset+0, 4, uid);
652                         offset += 4;
653
654                         if (!BYTES_ARE_IN_FRAME(offset,4)) return;
655                         gid = EXTRACT_UINT(pd,offset+0);
656                         if (tree)
657                                 proto_tree_add_item(tree, hf_rpc_auth_gid,
658                                         offset+0, 4, gid);
659                         offset += 4;
660
661                         if (!BYTES_ARE_IN_FRAME(offset,4)) return;
662                         gids_count = EXTRACT_UINT(pd,offset+0);
663                         if (tree) {
664                                 gitem = proto_tree_add_text(tree, offset, 4+gids_count*4,
665                                 "Auxiliary GIDs");
666                                 gtree = proto_item_add_subtree(gitem, ett_rpc_gids);
667                         }
668                         offset += 4;
669                         if (!BYTES_ARE_IN_FRAME(offset,4*gids_count)) return;
670                         for (gids_i = 0 ; gids_i < gids_count ; gids_i++) {
671                                 gids_entry = EXTRACT_UINT(pd,offset+0);
672                                 if (gtree)
673                                 proto_tree_add_item(gtree, hf_rpc_auth_gid,
674                                         offset, 4, gids_entry);
675                                 offset+=4;
676                         }
677                         /* how can I NOW change the gitem to print a list with
678                                 the first 16 gids? */
679                 }
680                 break;
681                 /*
682                 case AUTH_SHORT:
683
684                 break;
685                 */
686                 /* I have no tcpdump file with such a packet to verify the
687                         info from the RFC 1050 */
688                 /*
689                 case AUTH_DES:
690
691                 break;
692                 */
693                 default:
694                         if (length_full) {
695                                 if (tree)
696                                 proto_tree_add_text(tree,offset,
697                                 length_full, "opaque data");
698                         }
699         }
700 }
701
702 int
703 dissect_rpc_cred( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
704 {
705         guint length;
706         guint length_full;
707         proto_item *citem;
708         proto_tree *ctree;
709
710         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
711         length = EXTRACT_UINT(pd,offset+4);
712         length_full = rpc_roundup(length);
713         if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
714
715         if (tree) {
716                 citem = proto_tree_add_text(tree, offset, 8+length_full,
717                         "Credentials");
718                 ctree = proto_item_add_subtree(citem, ett_rpc_cred);
719                 dissect_rpc_auth(pd, offset, fd, ctree);
720         }
721         offset += 8 + length_full;
722
723         return offset;
724 }
725
726
727 int
728 dissect_rpc_verf( const u_char *pd, int offset, frame_data *fd, proto_tree *tree )
729 {
730         unsigned int length;
731         unsigned int length_full;
732         proto_item *vitem;
733         proto_tree *vtree;
734
735         if (!BYTES_ARE_IN_FRAME(offset,8)) return offset;
736         length = EXTRACT_UINT(pd,offset+4);
737         length_full = rpc_roundup(length);
738         if (!BYTES_ARE_IN_FRAME(offset+8,length_full)) return offset;
739
740         if (tree) {
741                 vitem = proto_tree_add_text(tree, offset, 8+length_full,
742                         "Verifier");
743                 vtree = proto_item_add_subtree(vitem, ett_rpc_verf);
744                 dissect_rpc_auth(pd, offset, fd, vtree);
745         }
746         offset += 8 + length_full;
747
748         return offset;
749 }
750
751
752 gboolean
753 dissect_rpc( const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
754 {
755         guint32 msg_type;
756         rpc_call_info rpc_key;
757         rpc_call_info *rpc_call = NULL;
758         rpc_prog_info_value *rpc_prog = NULL;
759         rpc_prog_info_key rpc_prog_key;
760
761         unsigned int xid;
762         unsigned int rpcvers;
763         unsigned int prog = 0;
764         unsigned int vers = 0;
765         unsigned int proc = 0;
766         int     proto = 0;
767         int     ett = 0;
768
769         unsigned int reply_state;
770         unsigned int accept_state;
771         unsigned int reject_state;
772
773         char *msg_type_name = NULL;
774         char *progname;
775         char *procname = NULL;
776         static char procname_static[20];
777
778         unsigned int vers_low;
779         unsigned int vers_high;
780
781         unsigned int auth_state;
782
783         proto_item *rpc_item=NULL;
784         proto_tree *rpc_tree = NULL;
785
786         proto_item *pitem=NULL;
787         proto_tree *ptree = NULL;
788         int offset_old = offset;
789
790         int use_rm = 0;
791         guint32 rpc_rm = 0;
792
793         rpc_call_info   rpc_call_msg;
794         rpc_proc_info_key       key;
795         rpc_proc_info_value     *value = NULL;
796         conversation_t* conversation;
797         static address null_address = { AT_NONE, 0, NULL };
798
799         dissect_function_t *dissect_function = NULL;
800
801         /* TCP uses record marking */
802         use_rm = (pi.ptype == PT_TCP);
803
804         /* the first 4 bytes are special in "record marking  mode" */
805         if (use_rm) {
806                 if (!BYTES_ARE_IN_FRAME(offset,4))
807                         return FALSE;
808                 rpc_rm = EXTRACT_UINT(pd,offset);
809                 offset += 4;
810         }
811
812         /*
813          * Check to see whether this looks like an RPC call or reply.
814          */
815         if (!BYTES_ARE_IN_FRAME(offset,8)) {
816                 /* Captured data in packet isn't enough to let us tell. */
817                 return FALSE;
818         }
819
820         /* both directions need at least this */
821         msg_type = EXTRACT_UINT(pd,offset+4);
822
823         switch (msg_type) {
824
825         case RPC_CALL:
826                 /* check for RPC call */
827                 if (!BYTES_ARE_IN_FRAME(offset,16)) {
828                         /* Captured data in packet isn't enough to let us
829                            tell. */
830                         return FALSE;
831                 }
832
833                 /* XID can be anything, we don't check it.
834                    We already have the message type.
835                    Check whether an RPC version number of 2 is in the
836                    location where it would be, and that an RPC program
837                    number we know about is in the locaton where it would be. */
838                 rpc_prog_key.prog = EXTRACT_UINT(pd,offset+12);
839                 if (EXTRACT_UINT(pd,offset+8) != 2 ||
840                     ((rpc_prog = g_hash_table_lookup(rpc_progs, &rpc_prog_key))
841                        == NULL)) {
842                         /* They're not, so it's probably not an RPC call. */
843                         return FALSE;
844                 }
845                 break;
846
847         case RPC_REPLY:
848                 /* Check for RPC reply.  A reply must match a call that
849                    we've seen, and the reply must be sent to the same
850                    port and address that the call came from, and must
851                    come from the port to which the call was sent.  (We
852                    don't worry about the address to which the call was
853                    sent and from which the reply was sent, because there's
854                    no guarantee that the reply will come from the address
855                    to which the call was sent.) */
856                 conversation = find_conversation(&null_address, &pi.dst,
857                     pi.ptype, pi.srcport, pi.destport);
858                 if (conversation == NULL) {
859                         /* We haven't seen an RPC call for that conversation,
860                            so we can't check for a reply to that call. */
861                         return FALSE;
862                 }
863
864                 /* The XIDs of the call and reply must match. */
865                 rpc_key.xid = EXTRACT_UINT(pd,offset+0);
866                 rpc_key.conversation = conversation;
867                 if ((rpc_call = rpc_call_lookup(&rpc_key)) == NULL) {
868                         /* The XID doesn't match a call from that
869                            conversation, so it's probably not an RPC reply. */
870                         return FALSE;
871                 }
872                 break;
873
874         default:
875                 /* The putative message type field contains neither
876                    RPC_CALL nor RPC_REPLY, so it's not an RPC call or
877                    reply. */
878                 return FALSE;
879         }
880
881         if (check_col(fd, COL_PROTOCOL))
882                 col_add_str(fd, COL_PROTOCOL, "RPC");
883
884         if (tree) {
885                 rpc_item = proto_tree_add_item(tree, proto_rpc, offset, END_OF_FRAME, NULL);
886                 if (rpc_item) {
887                         rpc_tree = proto_item_add_subtree(rpc_item, ett_rpc);
888                 }
889         }
890
891         if (use_rm && rpc_tree) {
892                 proto_tree_add_item(rpc_tree,hf_rpc_lastfrag,
893                         offset-4, 4, (rpc_rm >> 31) & 0x1);
894                 proto_tree_add_item(rpc_tree,hf_rpc_fraglen,
895                         offset-4, 4, rpc_rm & RPC_RM_FRAGLEN);
896         }
897
898         xid      = EXTRACT_UINT(pd,offset+0);
899         if (rpc_tree) {
900                 proto_tree_add_uint_format(rpc_tree,hf_rpc_xid,
901                         offset+0, 4, xid, "XID: 0x%x (%u)", xid, xid);
902         }
903
904         msg_type_name = val_to_str(msg_type,rpc_msg_type,"%u");
905         if (rpc_tree) {
906                 proto_tree_add_item(rpc_tree, hf_rpc_msgtype,
907                         offset+4, 4, msg_type);
908         }
909
910         offset += 8;
911
912         if (msg_type==RPC_CALL) {
913                 /* we know already the proto-entry, the ETT-const,
914                    and "rpc_prog" */
915                 proto = rpc_prog->proto;
916                 ett = rpc_prog->ett;
917                 progname = rpc_prog->progname;
918
919                 rpcvers = EXTRACT_UINT(pd,offset+0);
920                 if (rpc_tree) {
921                         proto_tree_add_item(rpc_tree,
922                                 hf_rpc_version, offset+0, 4, rpcvers);
923                 }
924
925                 prog = EXTRACT_UINT(pd,offset+4);
926                 
927                 if (rpc_tree) {
928                         proto_tree_add_uint_format(rpc_tree,
929                                 hf_rpc_program, offset+4, 4, prog,
930                                 "Program: %s (%u)", progname, prog);
931                 }
932                 
933                 if (check_col(fd, COL_PROTOCOL)) {
934                         /* Set the protocol name to the underlying
935                            program name. */
936                         col_add_fstr(fd, COL_PROTOCOL, "%s", progname);
937                 }
938
939                 if (!BYTES_ARE_IN_FRAME(offset+8,4))
940                         return TRUE;
941                 vers = EXTRACT_UINT(pd,offset+8);
942                 if (rpc_tree) {
943                         proto_tree_add_item(rpc_tree,
944                                 hf_rpc_programversion, offset+8, 4, vers);
945                 }
946
947                 if (!BYTES_ARE_IN_FRAME(offset+12,4))
948                         return TRUE;
949                 proc = EXTRACT_UINT(pd,offset+12);
950
951                 key.prog = prog;
952                 key.vers = vers;
953                 key.proc = proc;
954
955                 value = g_hash_table_lookup(rpc_procs,&key);
956                 if (value != NULL) {
957                         dissect_function = value->dissect_call;
958                         procname = value->name;
959                 }
960                 else {
961                         /* happens only with strange program versions or
962                            non-existing dissectors */
963                         dissect_function = NULL;
964                         sprintf(procname_static, "proc-%u", proc);
965                         procname = procname_static;
966                 }
967                 if (rpc_tree) {
968                         proto_tree_add_uint_format(rpc_tree,
969                                 hf_rpc_procedure, offset+12, 4, proc,
970                                 "Procedure: %s (%u)", procname, proc);
971                 }
972
973                 if (check_col(fd, COL_INFO)) {
974                         col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
975                                 vers,
976                                 procname,
977                                 msg_type_name,
978                                 xid);
979                 }
980
981                 /* Keep track of the address and port whence the call came,
982                    and the port to which the call is being sent, so that
983                    we can match up calls wityh replies.  (We don't worry
984                    about the address to which the call was sent and from
985                    which the reply was sent, because there's no
986                    guarantee that the reply will come from the address
987                    to which the call was sent.) */
988                 conversation = find_conversation(&pi.src, &null_address,
989                     pi.ptype, pi.srcport, pi.destport);
990                 if (conversation == NULL) {
991                         /* It's not part of any conversation - create a new one. */
992                         conversation = conversation_new(&pi.src, &null_address,
993                             pi.ptype, pi.srcport, pi.destport, NULL);
994                 }
995
996                 /* prepare the key data */
997                 rpc_call_msg.xid = xid;
998                 rpc_call_msg.conversation = conversation;
999
1000                 /* look up the request */
1001                 if (rpc_call_lookup(&rpc_call_msg)) {
1002                         /* duplicate request */
1003                         if (check_col(fd, COL_INFO)) {
1004                                 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
1005                                 if (rpc_tree) {
1006                                         proto_tree_add_item_hidden(rpc_tree,
1007                                                 hf_rpc_dup, 0,0, xid);
1008                                         proto_tree_add_item_hidden(rpc_tree,
1009                                                 hf_rpc_call_dup, 0,0, xid);
1010                                 }
1011                         }
1012                 }
1013                 else {
1014                         /* prepare the value data */
1015                         rpc_call_msg.replies = 0;
1016                         rpc_call_msg.prog = prog;
1017                         rpc_call_msg.vers = vers;
1018                         rpc_call_msg.proc = proc;
1019                         rpc_call_msg.proc_info = value;
1020                         /* store it */
1021                         rpc_call_insert(&rpc_call_msg);
1022                 }
1023
1024                 offset += 16;
1025
1026                 offset = dissect_rpc_cred(pd, offset, fd, rpc_tree);
1027                 offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
1028
1029                 /* go to the next dissector */
1030                 /* goto dissect_rpc_prog; */
1031
1032         } /* end of RPC call */
1033         else if (msg_type == RPC_REPLY)
1034         {
1035                 /* we know already the type from the calling routine,
1036                    and we already have "rpc_call" set above. */
1037                 prog = rpc_call->prog;
1038                 vers = rpc_call->vers;
1039                 proc = rpc_call->proc;
1040                 if (rpc_call->proc_info != NULL) {
1041                         dissect_function = rpc_call->proc_info->dissect_reply;
1042                         if (rpc_call->proc_info->name != NULL) {
1043                                 procname = rpc_call->proc_info->name;
1044                         }
1045                         else {
1046                                 sprintf(procname_static, "proc-%u", proc);
1047                                 procname = procname_static;
1048                         }
1049                 }
1050                 else {
1051                         dissect_function = NULL;
1052                         sprintf(procname_static, "proc-%u", proc);
1053                         procname = procname_static;
1054                 }
1055                 rpc_call->replies++;
1056
1057                 rpc_prog_key.prog = prog;
1058                 if ((rpc_prog = g_hash_table_lookup(rpc_progs,&rpc_prog_key)) == NULL) {
1059                         proto = 0;
1060                         ett = 0;
1061                         progname = "Unknown";
1062                 }
1063                 else {
1064                         proto = rpc_prog->proto;
1065                         ett = rpc_prog->ett;
1066                         progname = rpc_prog->progname;
1067
1068                         if (check_col(fd, COL_PROTOCOL)) {
1069                                 /* Set the protocol name to the underlying
1070                                    program name. */
1071                                 col_add_fstr(fd, COL_PROTOCOL, "%s",
1072                                     progname);
1073                         }
1074                 }
1075
1076                 if (check_col(fd, COL_INFO)) {
1077                         col_add_fstr(fd, COL_INFO,"V%u %s %s XID 0x%x",
1078                                 vers,
1079                                 procname,
1080                                 msg_type_name,
1081                                 xid);
1082                 }
1083
1084                 if (rpc_tree) {
1085                         proto_tree_add_uint_format(rpc_tree,
1086                                 hf_rpc_program, 0, 0, prog,
1087                                 "Program: %s (%u)", progname, prog);
1088                         proto_tree_add_item(rpc_tree,
1089                                 hf_rpc_programversion, 0, 0, vers);
1090                         proto_tree_add_uint_format(rpc_tree,
1091                                 hf_rpc_procedure, 0, 0, proc,
1092                                 "Procedure: %s (%u)", procname, proc);
1093                 }
1094
1095                 if (rpc_call->replies>1) {
1096                         if (check_col(fd, COL_INFO)) {
1097                                 col_append_fstr(fd, COL_INFO, " dup XID 0x%x", xid);
1098                                 if (rpc_tree) {
1099                                         proto_tree_add_item_hidden(rpc_tree,
1100                                                 hf_rpc_dup, 0,0, xid);
1101                                         proto_tree_add_item_hidden(rpc_tree,
1102                                                 hf_rpc_reply_dup, 0,0, xid);
1103                                 }
1104                         }
1105                 }
1106
1107                 if (!BYTES_ARE_IN_FRAME(offset,4))
1108                         return TRUE;
1109                 reply_state = EXTRACT_UINT(pd,offset+0);
1110                 if (rpc_tree) {
1111                         proto_tree_add_item(rpc_tree, hf_rpc_state_reply,
1112                                 offset+0, 4, reply_state);
1113                 }
1114                 offset += 4;
1115
1116                 if (reply_state == MSG_ACCEPTED) {
1117                         offset = dissect_rpc_verf(pd, offset, fd, rpc_tree);
1118                         if (!BYTES_ARE_IN_FRAME(offset,4))
1119                                 return TRUE;
1120                         accept_state = EXTRACT_UINT(pd,offset+0);
1121                         if (rpc_tree) {
1122                                 proto_tree_add_item(rpc_tree, hf_rpc_state_accept,
1123                                         offset+0, 4, accept_state);
1124                         }
1125                         offset += 4;
1126                         switch (accept_state) {
1127                                 case SUCCESS:
1128                                         /* now goto the lower protocol */
1129                                         goto dissect_rpc_prog;
1130                                 break;
1131                                 case PROG_MISMATCH:
1132                                         if (!BYTES_ARE_IN_FRAME(offset,8))
1133                                                 return TRUE;
1134                                         vers_low = EXTRACT_UINT(pd,offset+0);
1135                                         vers_high = EXTRACT_UINT(pd,offset+4);
1136                                         if (rpc_tree) {
1137                                                 proto_tree_add_item(rpc_tree,
1138                                                         hf_rpc_programversion_min,
1139                                                         offset+0, 4, vers_low);
1140                                                 proto_tree_add_item(rpc_tree,
1141                                                         hf_rpc_programversion_max,
1142                                                         offset+4, 4, vers_high);
1143                                         }
1144                                         offset += 8;
1145                                 break;
1146                                 default:
1147                                         /* void */
1148                                 break;
1149                         }
1150                 } else if (reply_state == MSG_DENIED) {
1151                         if (!BYTES_ARE_IN_FRAME(offset,4))
1152                                 return TRUE;
1153                         reject_state = EXTRACT_UINT(pd,offset+0);
1154                         if (rpc_tree) {
1155                                 proto_tree_add_item(rpc_tree,
1156                                         hf_rpc_state_reject, offset+0, 4,
1157                                         reject_state);
1158                         }
1159                         offset += 4;
1160
1161                         if (reject_state==RPC_MISMATCH) {
1162                                 if (!BYTES_ARE_IN_FRAME(offset,8))
1163                                         return TRUE;
1164                                 vers_low = EXTRACT_UINT(pd,offset+0);
1165                                 vers_high = EXTRACT_UINT(pd,offset+4);
1166                                 if (rpc_tree) {
1167                                         proto_tree_add_item(rpc_tree,
1168                                                 hf_rpc_version_min,
1169                                                 offset+0, 4, vers_low);
1170                                         proto_tree_add_item(rpc_tree,
1171                                                 hf_rpc_version_max,
1172                                                 offset+4, 4, vers_high);
1173                                 }
1174                                 offset += 8;
1175                         } else if (reject_state==AUTH_ERROR) {
1176                                 if (!BYTES_ARE_IN_FRAME(offset,4))
1177                                         return TRUE;
1178                                 auth_state = EXTRACT_UINT(pd,offset+0);
1179                                 if (rpc_tree) {
1180                                         proto_tree_add_item(rpc_tree,
1181                                                 hf_rpc_state_auth, offset+0, 4,
1182                                                 auth_state);
1183                                 }
1184                                 offset += 4;
1185                         }
1186                 } 
1187         } /* end of RPC reply */
1188
1189 dissect_rpc_prog:
1190         /* I know, goto is evil but it works as it is. */
1191
1192         /* now we know, that RPC was shorter */
1193         if (rpc_item) {
1194                 proto_item_set_len(rpc_item, offset - offset_old);
1195         }
1196
1197         /* create here the program specific sub-tree */
1198         if (tree) {
1199                 pitem = proto_tree_add_item(tree, proto, offset, END_OF_FRAME);
1200                 if (pitem) {
1201                         ptree = proto_item_add_subtree(pitem, ett);
1202                 }
1203
1204                 if (ptree) {
1205                         proto_tree_add_item(ptree,
1206                                 hf_rpc_programversion, 0, 0, vers);
1207                         proto_tree_add_uint_format(ptree,
1208                                 hf_rpc_procedure, 0, 0, proc,
1209                                 "Procedure: %s (%u)", procname, proc);
1210                 }
1211         }
1212
1213         /* call a specific dissection */
1214         if (dissect_function != NULL) {
1215                 offset = dissect_function(pd, offset, fd, ptree);
1216         }
1217
1218         /* dissect any remaining bytes (incomplete dissection) as pure data in
1219            the ptree */
1220         dissect_data(pd, offset, fd, ptree);
1221
1222         return TRUE;
1223 }
1224
1225
1226 /* Discard any state we've saved. */
1227 static void
1228 rpc_init_protocol(void)
1229 {
1230         memset(rpc_call_table, '\0', sizeof rpc_call_table);
1231         rpc_call_index = 0;
1232         rpc_call_firstfree = 0;
1233 }
1234
1235
1236 /* will be called once from register.c at startup time */
1237 void
1238 proto_register_rpc(void)
1239 {
1240         static hf_register_info hf[] = {
1241                 { &hf_rpc_lastfrag, {
1242                         "Last Fragment", "rpc.lastfrag", FT_BOOLEAN, BASE_NONE,
1243                         &yesno, 0, "Last Fragment" }},
1244                 { &hf_rpc_fraglen, {
1245                         "Fragment Length", "rpc.fraglen", FT_UINT32, BASE_DEC,
1246                         NULL, 0, "Fragment Length" }},
1247                 { &hf_rpc_xid, {
1248                         "XID", "rpc.xid", FT_UINT32, BASE_HEX,
1249                         NULL, 0, "XID" }},
1250                 { &hf_rpc_msgtype, {
1251                         "Message Type", "rpc.msgtyp", FT_UINT32, BASE_DEC,
1252                         VALS(rpc_msg_type), 0, "Message Type" }},
1253                 { &hf_rpc_state_reply, {
1254                         "Reply State", "rpc.replystat", FT_UINT32, BASE_DEC,
1255                         VALS(rpc_reply_state), 0, "Reply State" }},
1256                 { &hf_rpc_state_accept, {
1257                         "Accept State", "rpc.state_accept", FT_UINT32, BASE_DEC,
1258                         VALS(rpc_accept_state), 0, "Accept State" }},
1259                 { &hf_rpc_state_reject, {
1260                         "Reject State", "rpc.state_reject", FT_UINT32, BASE_DEC,
1261                         VALS(rpc_reject_state), 0, "Reject State" }},
1262                 { &hf_rpc_state_auth, {
1263                         "Auth State", "rpc.state_auth", FT_UINT32, BASE_DEC,
1264                         VALS(rpc_auth_state), 0, "Auth State" }},
1265                 { &hf_rpc_version, {
1266                         "RPC Version", "rpc.version", FT_UINT32, BASE_DEC,
1267                         NULL, 0, "RPC Version" }},
1268                 { &hf_rpc_version_min, {
1269                         "RPC Version (Minimum)", "rpc.version.min", FT_UINT32, 
1270                         BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1271                 { &hf_rpc_version_max, {
1272                         "RPC Version (Maximum)", "rpc.version.max", FT_UINT32, 
1273                         BASE_DEC, NULL, 0, "RPC Version (Maximum)" }},
1274                 { &hf_rpc_program, {
1275                         "Program", "rpc.program", FT_UINT32, BASE_DEC,
1276                         NULL, 0, "Program" }},
1277                 { &hf_rpc_programversion, {
1278                         "Program Version", "rpc.programversion", FT_UINT32, 
1279                         BASE_DEC, NULL, 0, "Program Version" }},
1280                 { &hf_rpc_programversion_min, {
1281                         "Program Version (Minimum)", "rpc.programversion.min", FT_UINT32, 
1282                         BASE_DEC, NULL, 0, "Program Version (Minimum)" }},
1283                 { &hf_rpc_programversion_max, {
1284                         "Program Version (Maximum)", "rpc.programversion.max", FT_UINT32, 
1285                         BASE_DEC, NULL, 0, "Program Version (Maximum)" }},
1286                 { &hf_rpc_procedure, {
1287                         "Procedure", "rpc.procedure", FT_UINT32, BASE_DEC,
1288                         NULL, 0, "Procedure" }},
1289                 { &hf_rpc_auth_flavor, {
1290                         "Flavor", "rpc.auth.flavor", FT_UINT32, BASE_DEC,
1291                         VALS(rpc_auth_flavor), 0, "Flavor" }},
1292                 { &hf_rpc_auth_length, {
1293                         "Length", "rpc.auth.length", FT_UINT32, BASE_DEC,
1294                         NULL, 0, "Length" }},
1295                 { &hf_rpc_auth_stamp, {
1296                         "Stamp", "rpc.auth.stamp", FT_UINT32, BASE_HEX,
1297                         NULL, 0, "Stamp" }},
1298                 { &hf_rpc_auth_uid, {
1299                         "UID", "rpc.auth.uid", FT_UINT32, BASE_DEC,
1300                         NULL, 0, "UID" }},
1301                 { &hf_rpc_auth_gid, {
1302                         "GID", "rpc.auth.gid", FT_UINT32, BASE_DEC,
1303                         NULL, 0, "GID" }},
1304                 { &hf_rpc_auth_machinename, {
1305                         "Machine Name", "rpc.auth.machinename", FT_STRING, 
1306                         BASE_DEC, NULL, 0, "Machine Name" }},
1307                 { &hf_rpc_dup, {
1308                         "Duplicate Transaction", "rpc.dup", FT_UINT32, BASE_DEC,
1309                         NULL, 0, "Duplicate Transaction" }},
1310                 { &hf_rpc_call_dup, {
1311                         "Duplicate Call", "rpc.call.dup", FT_UINT32, BASE_DEC,
1312                         NULL, 0, "Duplicate Call" }},
1313                 { &hf_rpc_reply_dup, {
1314                         "Duplicate Reply", "rpc.reply.dup", FT_UINT32, BASE_DEC,
1315                         NULL, 0, "Duplicate Reply" }},
1316                 { &hf_rpc_value_follows, {
1317                         "Value Follows", "rpc.value_follows", FT_BOOLEAN, BASE_NONE,
1318                         &yesno, 0, "Value Follows" }}
1319         };
1320         static gint *ett[] = {
1321                 &ett_rpc,
1322                 &ett_rpc_string,
1323                 &ett_rpc_cred,
1324                 &ett_rpc_verf,
1325                 &ett_rpc_gids,
1326         };
1327
1328         proto_rpc = proto_register_protocol("Remote Procedure Call", "rpc");
1329         proto_register_field_array(proto_rpc, hf, array_length(hf));
1330         proto_register_subtree_array(ett, array_length(ett));
1331         register_init_routine(&rpc_init_protocol);
1332
1333         /*
1334          * Init the hash tables.  Dissectors for RPC protocols must
1335          * have a "handoff registration" routine that registers the
1336          * protocol with RPC; they must not do it in their protocol
1337          * registration routine, as their protocol registration
1338          * routine might be called before this routine is called and
1339          * thus might be called before the hash tables are initialized,
1340          * but it's guaranteed that all protocol registration routines
1341          * will be called before any handoff registration routines
1342          * are called.
1343          */
1344         rpc_progs = g_hash_table_new(rpc_prog_hash, rpc_prog_equal);
1345         rpc_procs = g_hash_table_new(rpc_proc_hash, rpc_proc_equal);
1346 }