add tethereal_static
[obnox/wireshark/wip.git] / packet-diameter.c
1 /* packet-diameter.c
2  * Routines for DIAMETER packet disassembly
3  *
4  * $Id: packet-diameter.c,v 1.8 2000/11/19 08:53:56 guy Exp $
5  *
6  * Copyright (c) 2000 by David Frascone <chaos@mindspring.com>
7  *
8  * Ethereal - Network traffic analyzer
9  * By Johan Feyaerts
10  * Copyright 1999 Johan Feyaerts
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33
34 #ifdef HAVE_NETINET_IN_H
35 #include <netinet/in.h>
36 #endif
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <time.h>
43 #include <glib.h>
44 #include "packet.h"
45 #include "resolv.h"
46 #include "prefs.h"
47
48 /* This must be defined before we include our dictionary defs */
49
50 typedef struct _value_value_pair {
51         guint16 val1;
52         guint16 val2;
53 } value_value_pair;
54
55 typedef enum {
56         DIAMETER_DATA=1,
57         DIAMETER_STRING,
58         DIAMETER_ADDRESS,
59         DIAMETER_INTEGER32,
60         DIAMETER_INTEGER64,
61         DIAMETER_TIME,
62         DIAMETER_COMPLEX
63 } diameterDataTypes;
64
65 #include "packet-diameter.h"
66 #include "packet-diameter-defs.h"
67
68 #define COMMAND_CODE_OFFSET 20
69 #define  NTP_TIME_DIFF                   (2208988800UL)
70
71 #undef SCTP_DISSECTORS_ENABLED
72
73 #define UDP_PORT_DIAMETER       2645
74 #define TCP_PORT_DIAMETER       1812
75 #ifdef SCTP_DISSECTORS_ENABLED
76 #define SCTP_PORT_DIAMETER      1812
77 #endif
78 /* #define UDP_PORT_DIAMETER    1812  -- Compiling this in breaks RADIUS */
79
80 static int proto_diameter = -1;
81 static int hf_diameter_length = -1;
82 static int hf_diameter_code = -1;
83 static int hf_diameter_id =-1;
84 static int hf_diameter_flags = -1;
85 static int hf_diameter_ns = -1;
86 static int hf_diameter_nr = -1;
87
88 static gint ett_diameter = -1;
89 static gint ett_diameter_avp = -1;
90 static gint ett_diameter_avpinfo = -1;
91
92 static char gbl_diameterString[200];
93 static int gbl_diameterUdpPort=UDP_PORT_DIAMETER;
94 static int gbl_diameterTcpPort=TCP_PORT_DIAMETER;
95 #ifdef SCTP_DISSECTORS_ENABLED
96 static int gbl_diameterSctpPort=SCTP_PORT_DIAMETER;
97 #endif
98 gboolean gbl_commandCodeInHeader = FALSE;
99
100 typedef struct _e_diameterhdr {
101   guint8 code;                   /* Must be 254 for diameter */
102   guint8 flagsVer;
103   guint16 pktLength;
104   guint32 identifier;
105   union {
106     struct {
107       guint16 nextSend;
108       guint16 nextReceived;
109     } old;
110     struct {
111       guint32 commandCode;
112       guint32 vendorId;
113       guint16 nextSend;
114       guint16 nextReceived;
115     } new;
116   } u;
117 } e_diameterhdr;
118
119 typedef struct _e_avphdr {
120   guint32 avp_type;
121   guint16 avp_length;
122   guint16 avp_flags;
123   guint32 avp_vendorId;           /* optional */
124   guint32 avp_tag;                /* optional */
125   
126 } e_avphdr;
127
128 #define AUTHENTICATOR_LENGTH 12
129
130 #define DIAM_FLAGS_A 0x10
131 #define DIAM_FLAGS_W 0x08
132 #define AVP_FLAGS_P 0x0010
133 #define AVP_FLAGS_T 0x0008
134 #define AVP_FLAGS_V 0x0004
135 #define AVP_FLAGS_R 0x0002
136 #define AVP_FLAGS_M 0x0001
137
138 void proto_reg_handoff_diameter(void);
139
140 static guint32 match_numval(guint32 val, const value_value_pair *vs)
141 {
142   guint32 i = 0;
143
144   while (vs[i].val1) {
145     if (vs[i].val1 == val)
146       return(vs[i].val2);
147     i++;
148   }
149
150   return(0);
151 }
152
153 static gchar *rdconvertbufftostr(gchar *dest,guint8 length,const guint8 *pd)
154 {
155 /*converts the raw buffer into printable text */
156 guint32 i;
157 guint32 totlen=0;
158
159         dest[0]='"';
160         dest[1]=0;
161         totlen=1;
162         for (i=0; i < (guint32)length; i++)
163         {
164                 if( isalnum((int)pd[i])||ispunct((int)pd[i])
165                                 ||((int)pd[i]==' '))            {
166                         dest[totlen]=(gchar)pd[i];
167                         totlen++;
168                 }
169                 else
170                 {
171                         sprintf(&(dest[totlen]), "\\%03u", pd[i]);
172                         totlen=totlen+strlen(&(dest[totlen]));
173                 }
174         }
175         dest[totlen]='"';
176         dest[totlen+1]=0;
177         return dest;
178 }
179
180 static gchar *rd_match_strval(guint32 val, const value_string *vs) {
181         gchar           *result;
182         result=match_strval(val,vs);
183         if (result == NULL ) {
184                 result="Undefined";
185         }
186         return result;
187 }
188 static char *complexValCheck(e_avphdr *avp, const char *data, size_t dataLen)
189 {
190         const char *rawData;
191         static char returnStr[1024];
192
193         switch (avp->avp_type) {
194         case DIAMETER_ATT_INTEGRITY_CHECK_VALUE:
195         {
196                 struct {
197                         guint32 transform;
198                         guint32 keyid;
199                 } icv;
200                 
201                 memcpy(&icv, data, 8);
202                 icv.transform=ntohl(icv.transform);
203                 icv.keyid=ntohl(icv.keyid);
204                 rawData = &data[8];
205
206                 sprintf(returnStr, 
207                     "transform: 0x%08x (%d) keyid: 0x%08x (%d) Hash: ",
208                     icv.transform, icv.transform, icv.keyid, icv.keyid);
209                 
210                 rdconvertbufftostr(&returnStr[strlen(returnStr)],
211                     dataLen-8,
212                     rawData);
213                 return returnStr;
214         }
215         }
216
217         return NULL;;
218 } /* complexValCheck */
219 static char *customValCheck(int code, int value)
220 {
221         switch (code) {
222         case DIAMETER_ATT_QOS_SERVICE_TYPE:
223                 return rd_match_strval(value, diameter_qos_service_type_vals);
224                 break;
225         case DIAMETER_ATT_SERVICE_TYPE:
226                 return rd_match_strval(value, diameter_service_type_vals);
227                 break;
228         case DIAMETER_ATT_PROHIBIT:
229                 return rd_match_strval(value, diameter_prohibit_vals);
230                 break;
231         case DIAMETER_ATT_PROMPT:
232                 return rd_match_strval(value, diameter_prompt_vals);
233                 break;
234         case DIAMETER_ATT_SOURCE_PORT:
235                 return rd_match_strval(value, diameter_source_port_vals);
236                 break;
237         case DIAMETER_ATT_NAS_PORT_TYPE:
238                 return rd_match_strval(value, diameter_nas_port_type_vals);
239                 break;
240         case DIAMETER_ATT_INTERFACE_ADDRESS:
241                 return rd_match_strval(value, diameter_interface_address_vals);
242                 break;
243         case DIAMETER_ATT_FRAMED_ROUTING:
244                 return rd_match_strval(value, diameter_framed_routing_vals);
245                 break;
246         case DIAMETER_ATT_COMMAND_CODE:
247                 return rd_match_strval(value, diameter_command_code_vals);
248                 break;
249         case DIAMETER_ATT_FRAMED_IP_ADDRESS:
250                 return rd_match_strval(value, diameter_framed_ip_address_vals);
251                 break;
252         case DIAMETER_ATT_ARAP_ZONE_ACCESS:
253                 return rd_match_strval(value, diameter_arap_zone_access_vals);
254                 break;
255         case DIAMETER_ATT_ACCT_AUTHENTIC:
256                 return rd_match_strval(value, diameter_acct_authentic_vals);
257                 break;
258         case DIAMETER_ATT_FRAMED_PROTOCOL:
259                 return rd_match_strval(value, diameter_framed_protocol_vals);
260                 break;
261         case DIAMETER_ATT_FRAMED_COMPRESSION:
262                 return rd_match_strval(value, diameter_framed_compression_vals);
263                 break;
264         case DIAMETER_ATT_AUTHENTICATION_TYPE:
265                 return rd_match_strval(value, diameter_authentication_type_vals);
266                 break;
267         case DIAMETER_ATT_ACCT_TERMINATE_CAUSE:
268                 return rd_match_strval(value, diameter_acct_terminate_cause_vals);
269                 break;
270         case DIAMETER_ATT_PROTOCOL:
271                 return rd_match_strval(value, diameter_protocol_vals);
272                 break;
273         case DIAMETER_ATT_DESTINATION_PORT:
274                 return rd_match_strval(value, diameter_destination_port_vals);
275                 break;
276         case DIAMETER_ATT_TERMINATION_ACTION:
277                 return rd_match_strval(value, diameter_termination_action_vals);
278                 break;
279         case DIAMETER_ATT_EXTENSION_ID:
280                 return rd_match_strval(value, diameter_extension_id_vals);
281                 break;
282         case DIAMETER_ATT_MERIT_LAS_CODE:
283                 return rd_match_strval(value, diameter_merit_las_code_vals);
284                 break;
285         case DIAMETER_ATT_LOGIN_SERVICE:
286                 return rd_match_strval(value, diameter_login_service_vals);
287                 break;
288         case DIAMETER_ATT_RSVP_SERVICE_TYPE:
289                 return rd_match_strval(value, diameter_rsvp_service_type_vals);
290                 break;
291         case DIAMETER_ATT_REBOOT_TYPE:
292                 return rd_match_strval(value, diameter_reboot_type_vals);
293                 break;
294         case DIAMETER_ATT_ACCT_STATUS_TYPE:
295                 return rd_match_strval(value, diameter_acct_status_type_vals);
296                 break;
297         }
298
299         return NULL;
300 }
301
302 static gchar *rd_value_to_str(e_avphdr *avph,const u_char *pd, int offset)
303 {
304         int print_type;
305         gchar *cont;
306         guint32 intval;
307         int dataLen;
308         char *valstr;
309         static char buffer[1024];
310
311         dataLen = avph->avp_length - sizeof(e_avphdr);
312
313         if (!(avph->avp_flags & AVP_FLAGS_V))
314                 dataLen += 4;
315         if (!(avph->avp_flags & AVP_FLAGS_T))
316                 dataLen += 4;
317
318 /* prints the values of the attribute value pairs into a text buffer */
319         
320         print_type=match_numval(avph->avp_type,diameter_printinfo);
321         /* Default begin */
322         sprintf(buffer,"Value: ");
323         cont=&buffer[strlen(buffer)];
324         switch(print_type)
325                 {
326                 case DIAMETER_COMPLEX:
327                         valstr=complexValCheck(avph, &(pd[offset]), dataLen);
328                         if (valstr) {
329                                 strcpy(cont, valstr);
330                                 break;
331                         }
332                                 
333                         /* Intentional fall through */
334                 case DIAMETER_DATA:
335                 case DIAMETER_STRING:
336                         rdconvertbufftostr(cont,dataLen,
337                             &(pd[offset]));
338                         break;
339                 case DIAMETER_ADDRESS:
340                         sprintf(cont,"%u.%u.%u.%u",(guint8)pd[offset],
341                             (guint8)pd[offset+1],(guint8)pd[offset+2],
342                             (guint8)pd[offset+3]);
343                         break;
344                 case DIAMETER_INTEGER32:
345                         /* Check for custom values */
346                         intval=pntohl(&(pd[offset]));
347                         valstr=customValCheck(avph->avp_type, intval);
348                         if (valstr) {
349                                 sprintf(cont,"%s (%u)", valstr, intval);
350                         } else {
351                                 sprintf(cont,"%u", intval);
352                         }
353                         break;
354                 case DIAMETER_INTEGER64:
355                         sprintf(cont,"Unsupported Conversion");
356                         break;
357                 case DIAMETER_TIME:
358                 {
359                         struct tm lt;
360                         intval=pntohl(&(pd[offset]));
361                         intval -= NTP_TIME_DIFF;
362                         lt=*localtime((time_t *)&intval);
363                         strftime(cont, 1024, 
364                             "%a, %d %b %Y %H:%M:%S %z",&lt);
365                 }
366                 break;
367                         
368                 default:
369                         rdconvertbufftostr(cont,dataLen,
370                             &(pd[offset]));
371                         break;
372                 }
373         if (cont == buffer) {
374                 strcpy(cont,"Unknown Value");
375         }
376         return buffer;
377 }
378
379
380 static void dissect_attribute_value_pairs(const u_char *pd, int offset,
381     frame_data *fd, proto_tree *tree, int avplength) {
382 /* adds the attribute value pairs to the tree */
383         e_avphdr avph;
384         gchar *avptpstrval;
385         gchar *valstr;
386         guint32 tag=0;
387         guint32 vendorId=0;
388         int dataOffset;
389         int fixAmt;
390         proto_item *avptf;
391         proto_tree *avptree;
392         int vendorOffset, tagOffset;
393         
394         if (avplength==0) {
395                 proto_tree_add_text(tree, NullTVB,offset,0,
396                     "No Attribute Value Pairs Found");
397                 return;
398         }
399         
400         while (avplength > 0 ) {
401                 vendorOffset = tagOffset = 0;
402                 memcpy(&avph,&pd[offset],sizeof(e_avphdr));
403                 avph.avp_type = ntohl(avph.avp_type);
404                 avph.avp_length = ntohs(avph.avp_length);
405                 avph.avp_flags = ntohs(avph.avp_flags);
406                 
407                 if (avph.avp_flags & AVP_FLAGS_V) {
408                         vendorId = ntohl(avph.avp_vendorId);
409                         vendorOffset = 8;
410                         if (avph.avp_flags & AVP_FLAGS_T) {
411                                 tag = ntohl(avph.avp_tag);
412                                 tagOffset = 12;
413                                 dataOffset = sizeof(e_avphdr);
414                         } else {
415                                 /* only a vendor id */
416                                 dataOffset = sizeof(e_avphdr) - sizeof(guint32);
417                         }
418                 } else {
419                         if (avph.avp_flags & AVP_FLAGS_T) {
420                                 /* tag in vendor field */
421                                 tag = ntohl(avph.avp_vendorId);
422                                 tagOffset = 8;
423                                 dataOffset = sizeof(e_avphdr) - sizeof(guint32);
424                         } else {
425                                 /* No vendor or tag info */
426                                 dataOffset = sizeof(e_avphdr) -
427                                     (2*sizeof(guint32));
428                         }
429                 }
430                 
431                 /*
432                  * Fix byte-alignment
433                  */
434                 fixAmt = 4 - (avph.avp_length % 4);
435                 if (fixAmt == 4) fixAmt = 0;
436                 avplength=avplength - (avph.avp_length + fixAmt);
437                 avptpstrval=match_strval(avph.avp_type, diameter_attrib_type_vals);
438                 if (avptpstrval == NULL) avptpstrval="Unknown Type";
439                 if (!BYTES_ARE_IN_FRAME(offset, avph.avp_length)) {
440                         break;
441                 }
442                 avptf = proto_tree_add_text(tree,NullTVB,
443                     offset, avph.avp_length,
444                     "%s(%d) l:0x%x (%d bytes)",
445                     avptpstrval,avph.avp_type,avph.avp_length,
446                     avph.avp_length);
447                 avptree = proto_item_add_subtree(avptf,
448                     ett_diameter_avpinfo);
449                 if (avptree !=NULL) {
450                         proto_tree_add_text(avptree,NullTVB,
451                             offset, 4,
452                             "AVP Code: %s(%d)",
453                             avptpstrval,avph.avp_type);
454                         proto_tree_add_text(avptree,NullTVB,
455                             offset+4 , 2,
456                             "Length: 0x%x(%d bytes)",
457                             avph.avp_length, avph.avp_length);
458                         proto_tree_add_text(avptree,NullTVB,
459                             offset+6, 2,
460                             "Flags: P:%d T:%d V:%d R:%d M:%d",
461                             (avph.avp_flags & AVP_FLAGS_P)?1:0,
462                             (avph.avp_flags & AVP_FLAGS_T)?1:0,
463                             (avph.avp_flags & AVP_FLAGS_V)?1:0,
464                             (avph.avp_flags & AVP_FLAGS_R)?1:0,
465                             (avph.avp_flags & AVP_FLAGS_M)?1:0);
466                         if (vendorOffset) {
467                                 proto_tree_add_text(avptree,NullTVB,
468                                     offset+vendorOffset, 4,
469                                     "VendorId: 0x%08x (%d)",
470                                     vendorId, vendorId);
471                         }
472                         if (tagOffset) {
473                                 proto_tree_add_text(avptree,NullTVB,
474                                     offset+tagOffset, 4,
475                                     "Tag: 0x%08x (%d)",
476                                     tag, tag);
477                         }
478                         valstr=rd_value_to_str(&avph, pd, offset+dataOffset);
479                         proto_tree_add_text(avptree,NullTVB,
480                             offset+dataOffset, avph.avp_length - dataOffset,
481                             "Data: (%d bytes) %s",
482                             avph.avp_length - dataOffset, valstr);
483                 }
484                 offset=offset+avph.avp_length + fixAmt;
485         }
486 }
487
488 void dissect_diameter(const u_char *pd, int offset, frame_data *fd, 
489     proto_tree *tree)
490 {
491   proto_tree *diameter_tree,*avptree;
492   proto_item *ti,*avptf;
493   int avplength,hdrlength, offsetavp;
494   e_diameterhdr dh;
495   int commandCode;
496   char buffer[2000];
497   int nextSend=0, nextReceived=0;
498   
499   gchar *codestrval;
500   
501   OLD_CHECK_DISPLAY_AS_DATA(proto_diameter, pd, offset, fd, tree);
502   
503   if (gbl_commandCodeInHeader) 
504     hdrlength=sizeof(e_diameterhdr);
505   else
506     hdrlength = sizeof(e_diameterhdr) - (2 * sizeof(guint32));
507
508   memcpy(&dh,&pd[offset],hdrlength);
509   /* Fix byte ordering in our static structure */
510   dh.pktLength = ntohs(dh.pktLength);
511   dh.identifier = ntohl(dh.identifier);
512   
513   /* Our code is in first avp */
514   if (gbl_commandCodeInHeader) {
515     dh.u.new.commandCode = ntohl(dh.u.new.commandCode);
516     dh.u.new.vendorId = ntohl(dh.u.new.vendorId);
517
518     if ((DIAM_FLAGS_W & dh.flagsVer)) {
519       dh.u.new.nextSend = ntohs(dh.u.new.nextSend);
520       dh.u.new.nextReceived = ntohs(dh.u.new.nextReceived);
521       nextSend = dh.u.new.nextSend;
522       nextReceived = dh.u.new.nextReceived;
523     } else {
524         hdrlength -= 4;
525     }
526     commandCode = dh.u.new.commandCode;
527   } else {
528     if ((DIAM_FLAGS_W & dh.flagsVer)) {
529       dh.u.old.nextSend = ntohs(dh.u.old.nextSend);
530       dh.u.old.nextReceived = ntohs(dh.u.old.nextReceived);
531       nextSend = dh.u.old.nextSend;
532       nextReceived = dh.u.old.nextReceived;
533     } else {
534         hdrlength -= 4;
535     }
536     memcpy(&commandCode, &pd[offset+COMMAND_CODE_OFFSET], 4);
537     commandCode = ntohl(commandCode);
538   }
539   
540   codestrval=  match_strval(commandCode,diameter_command_code_vals);
541   if (codestrval==NULL) {
542     codestrval="Unknown Packet";
543   }
544   if (check_col(fd, COL_PROTOCOL))
545     col_set_str(fd, COL_PROTOCOL, "DIAMETER");
546   if (check_col(fd, COL_INFO)) {
547     if (DIAM_FLAGS_W & dh.flagsVer) {
548        if (DIAM_FLAGS_A & dh.flagsVer) {
549          sprintf(buffer,"ACK (id=%d, l=%d, s=%d, r=%d)",
550                  dh.identifier, dh.pktLength, nextSend,
551                  nextReceived);
552        } else {
553          sprintf(buffer,"%s(%d) (id=%d, l=%d, s=%d, r=%d)",
554                  codestrval,commandCode, dh.identifier, dh.pktLength,
555                  nextSend, nextReceived);
556        }
557     } else {
558        if (DIAM_FLAGS_A & dh.flagsVer) {
559          sprintf(buffer,"ACK (id=%d, l=%d)",
560                  dh.identifier, dh.pktLength);
561        } else {
562          sprintf(buffer,"%s(%d) (id=%d, l=%d)",
563                  codestrval,commandCode,
564                 dh.identifier, dh.pktLength);
565        }
566    }
567     col_add_fstr(fd,COL_INFO,buffer);
568   }
569   
570   if (tree) {
571     
572     ti = proto_tree_add_protocol_format(tree, proto_diameter, NullTVB,
573                                         offset, dh.pktLength, "%s",
574                                         gbl_diameterString);
575     diameter_tree = proto_item_add_subtree(ti, ett_diameter);
576     
577     if (!(DIAM_FLAGS_A & dh.flagsVer)) {
578       proto_tree_add_uint_format(diameter_tree,
579                                  hf_diameter_code,
580                                  NullTVB,
581                                  offset+0,
582                                  1, dh.code, "Packet code:0x%02x",
583                                  dh.code);
584     }
585     
586     proto_tree_add_uint_format(diameter_tree,
587                                hf_diameter_flags,
588                                NullTVB, offset+1, 1,
589                                dh.flagsVer,
590                                "Packet flags/Version: 0x%02x (Flags:0x%x,"
591                                " A:%d W:%d Version=0x%1x (%d)",
592                                dh.flagsVer, (dh.flagsVer&0xf8)>>3,
593                                (DIAM_FLAGS_A & dh.flagsVer)?1:0,
594                                (DIAM_FLAGS_W & dh.flagsVer)?1:0,
595                                dh.flagsVer&0x07, dh.flagsVer&0x07);
596     proto_tree_add_uint_format(diameter_tree,
597                                hf_diameter_length, NullTVB,
598                                offset+2, 2,
599                                dh.pktLength, 
600                                "Packet length: 0x%04x (%d)",dh.pktLength,
601                                dh.pktLength); 
602     proto_tree_add_uint_format(diameter_tree,hf_diameter_id,
603                                NullTVB, offset+4, 4,
604                                dh.identifier, "Packet identifier: 0x%08x (%d)",
605                                dh.identifier, dh.identifier);         
606     if (gbl_commandCodeInHeader) {
607       proto_tree_add_uint_format(diameter_tree,hf_diameter_id,
608                                  NullTVB, offset+8, 4,
609                                  dh.identifier, "Command Code: 0x%08x (%d:%s)",
610                                  dh.u.new.commandCode, dh.u.new.commandCode,
611                                  codestrval);         
612       proto_tree_add_uint_format(diameter_tree,hf_diameter_id,
613                                  NullTVB, offset+12, 4,
614                                  dh.identifier, "VendorId: 0x%08x (%d)",
615                                  dh.u.new.vendorId, dh.u.new.vendorId);         
616       if (DIAM_FLAGS_W & dh.flagsVer) {
617         proto_tree_add_uint_format(diameter_tree,
618                                    hf_diameter_ns, NullTVB,
619                                    offset+16, 2,
620                                    nextSend, 
621                                    "Ns: 0x%02x(%d)",nextSend, nextSend);
622         
623         proto_tree_add_uint_format(diameter_tree,
624                                    hf_diameter_nr, NullTVB,
625                                    offset+20, 2,
626                                    nextReceived, 
627                                    "Nr: 0x%02x(%d)", nextReceived,
628                                    nextReceived); 
629       }
630     } else {
631       if (DIAM_FLAGS_W & dh.flagsVer) {
632         proto_tree_add_uint_format(diameter_tree,
633                                    hf_diameter_ns, NullTVB,
634                                    offset+8, 2,
635                                    nextSend, 
636                                    "Ns: 0x%02x(%d)",nextSend, nextSend);
637         
638         proto_tree_add_uint_format(diameter_tree,
639                                    hf_diameter_nr, NullTVB,
640                                    offset+10, 2,
641                                    nextReceived, 
642                                    "Nr: 0x%02x(%d)", nextReceived,
643                                    nextReceived); 
644       }
645     }
646     
647     /* Update the lengths */
648     avplength= dh.pktLength -hdrlength;
649     offsetavp=offset+hdrlength;
650     
651     /* list the attribute value pairs */
652     
653     avptf = proto_tree_add_text(diameter_tree,
654                                 NullTVB,offset+hdrlength,avplength,
655                                 "Attribute value pairs");
656     avptree = proto_item_add_subtree(avptf,
657                                      ett_diameter_avp);
658     if (avptree !=NULL) {
659       dissect_attribute_value_pairs( pd,
660                                      offsetavp,fd,avptree,avplength);
661     }
662   }
663 }
664
665 /* registration with the filtering engine */
666 void
667 proto_register_diameter(void)
668 {
669         static hf_register_info hf[] = {
670                 { &hf_diameter_code,
671                   { "Code","diameter.code", FT_UINT8, BASE_DEC, NULL, 0x0,
672                     "" }},
673                 
674                 { &hf_diameter_flags,
675                   { "Flags+Version", "diameter.flags", FT_UINT8, BASE_DEC, NULL, 0x0,
676                     "" }},
677                 
678                 { &hf_diameter_length,
679                 { "Length","diameter.length", FT_UINT32, BASE_DEC, NULL, 0x0,
680                   "" }},
681                 
682                 { &hf_diameter_id,
683                 { "Identifier", "diameter.id", FT_UINT32, BASE_DEC, NULL, 0x0,
684                   "" }},
685
686                 { &hf_diameter_ns,
687                   { "Next Send",        "diameter.ns", FT_UINT16, BASE_DEC, NULL, 0x0,
688                     "" }},
689                 { &hf_diameter_nr,
690                   { "Next Received",    "diameter.nr", FT_UINT16, BASE_DEC, NULL, 0x0,
691                     "" }},
692
693         };
694         static gint *ett[] = {
695                 &ett_diameter,
696                 &ett_diameter_avp,
697                 &ett_diameter_avpinfo
698         };
699         module_t *diameter_module;
700         
701         /* Register a configuration option for port */
702         diameter_module = prefs_register_module("Diameter", "Diameter",
703             proto_reg_handoff_diameter);
704         prefs_register_uint_preference(diameter_module, "udp.port",
705                                        "DIAMETER UDP Port",
706                                        "Set the port for DIAMETER messages (if"
707                                        " other than RADIUS port)",
708                                        10,
709                                        &gbl_diameterUdpPort);
710         prefs_register_uint_preference(diameter_module, "tcp.port",
711                                        "DIAMETER TCP Port",
712                                        "Set the TCP port for DIAMETER messages",
713                                        10,
714                                        &gbl_diameterTcpPort);
715 #ifdef SCTP_DISSECTORS_ENABLED
716         prefs_register_uint_preference(diameter_module, "sctp.port",
717                                        "DIAMETER SCTP Port",
718                                        "Set the SCTP port for DIAMETER messages",
719                                        10,
720                                        &gbl_diameterSctpPort);
721 #endif
722         prefs_register_bool_preference(diameter_module, "command_in_header",
723                                        "Command code in header",
724                                        "Whether the command code is in the header, or in the first AVP",
725                                        &gbl_commandCodeInHeader);
726
727         proto_diameter = proto_register_protocol (gbl_diameterString, "diameter");
728         proto_register_field_array(proto_diameter, hf, array_length(hf));
729         proto_register_subtree_array(ett, array_length(ett));
730 }
731
732 void
733 proto_reg_handoff_diameter(void)
734 {
735         static int Initialized=FALSE;
736         static int UdpPort=0;
737         static int TcpPort=0;
738 #ifdef SCTP_DISSECTORS_ENABLED
739         static int SctpPort=0;
740 #endif
741         if (Initialized) {
742                 old_dissector_delete("udp.port", UdpPort, dissect_diameter);
743                 old_dissector_delete("tcp.port", TcpPort, dissect_diameter);
744 #ifdef SCTP_DISSECTORS_ENABLED
745                 old_dissector_delete("sctp.srcport", SctpPort, dissect_diameter);
746                 old_dissector_delete("sctp.destport", SctpPort, dissect_diameter);
747 #endif
748         } else {
749                 Initialized=TRUE;
750         }
751
752         /* set port for future deletes */
753         UdpPort=gbl_diameterUdpPort;
754         TcpPort=gbl_diameterTcpPort;
755 #ifdef SCTP_DISSECTORS_ENABLED
756         SctpPort=gbl_diameterSctpPort;
757 #endif
758
759         strcpy(gbl_diameterString, "Diameter Protocol");
760
761         /* g_warning ("Diameter: Adding tcp dissector to port %d",
762                 gbl_diameterTcpPort); */
763         old_dissector_add("tcp.port", gbl_diameterTcpPort, dissect_diameter);
764         old_dissector_add("udp.port", gbl_diameterUdpPort, dissect_diameter);
765 #ifdef SCTP_DISSECTORS_ENABLED
766         old_dissector_add("sctp.srcport", gbl_diameterSctpPort, dissect_diameter);
767         old_dissector_add("sctp.destport", gbl_diameterSctpPort, dissect_diameter);
768 #endif
769 }