Absolute and Relative times were swapped. Also add comment that there seems
[obnox/wireshark/wip.git] / packet-isakmp.c
1 /* packet-isakmp.c
2  * Routines for the Internet Security Association and Key Management Protocol
3  * (ISAKMP) (RFC 2408) and the Internet IP Security Domain of Interpretation
4  * for ISAKMP (RFC 2407)
5  * Brad Robel-Forrest <brad.robel-forrest@watchguard.com>
6  *
7  * $Id: packet-isakmp.c,v 1.53 2002/01/21 23:35:31 guy Exp $
8  *
9  * Ethereal - Network traffic analyzer
10  * By Gerald Combs <gerald@ethereal.com>
11  * Copyright 1998 Gerald Combs
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 <stdio.h>
37 #include <string.h>
38
39 #ifdef HAVE_NETINET_IN_H
40 #include <netinet/in.h>
41 #endif
42
43 #include <glib.h>
44
45 #ifdef NEED_SNPRINTF_H
46 # include "snprintf.h"
47 #endif
48
49 #include <epan/packet.h>
50 #include "ipproto.h"
51
52 static int proto_isakmp = -1;
53
54 static gint ett_isakmp = -1;
55 static gint ett_isakmp_flags = -1;
56 static gint ett_isakmp_payload = -1;
57
58 #define UDP_PORT_ISAKMP 500
59 #define TCP_PORT_ISAKMP 500
60
61 #define NUM_PROTO_TYPES 5
62 #define proto2str(t)    \
63   ((t < NUM_PROTO_TYPES) ? prototypestr[t] : "UNKNOWN-PROTO-TYPE")
64
65 static const char *prototypestr[NUM_PROTO_TYPES] = {
66   "RESERVED",
67   "ISAKMP",
68   "IPSEC_AH",
69   "IPSEC_ESP",
70   "IPCOMP"
71 };
72
73 #define NUM_P1_ATT_TYPES        17
74 #define p1_atttype2str(t)       \
75   ((t < NUM_P1_ATT_TYPES) ? p1_atttypestr[t] : "UNKNOWN-ATTRIBUTE-TYPE")
76
77 static const char *p1_atttypestr[NUM_P1_ATT_TYPES] = {
78   "UNKNOWN-ATTRIBUTE-TYPE",
79   "Encryption-Algorithm",
80   "Hash-Algorithm",
81   "Authentication-Method",
82   "Group-Description",
83   "Group-Type",
84   "Group-Prime",
85   "Group-Generator-One",
86   "Group-Generator-Two",
87   "Group-Curve-A",
88   "Group-Curve-B",
89   "Life-Type",
90   "Life-Duration",
91   "PRF",
92   "Key-Length",
93   "Field-Size",
94   "Group-Order"
95 };
96
97 #define NUM_ATT_TYPES   11
98 #define atttype2str(t)  \
99   ((t < NUM_ATT_TYPES) ? atttypestr[t] : "UNKNOWN-ATTRIBUTE-TYPE")
100
101 static const char *atttypestr[NUM_ATT_TYPES] = {
102   "UNKNOWN-ATTRIBUTE-TYPE",
103   "SA-Life-Type",
104   "SA-Life-Duration",
105   "Group-Description",
106   "Encapsulation-Mode",
107   "Authentication-Algorithm",
108   "Key-Length",
109   "Key-Rounds",
110   "Compress-Dictinary-Size",
111   "Compress-Private-Algorithm",
112   "ECN Tunnel"
113 };
114
115 #define NUM_TRANS_TYPES 2
116 #define trans2str(t)    \
117   ((t < NUM_TRANS_TYPES) ? transtypestr[t] : "UNKNOWN-TRANS-TYPE")
118
119 static const char *transtypestr[NUM_TRANS_TYPES] = {
120   "RESERVED",
121   "KEY_IKE"
122 };
123
124 #define NUM_AH_TRANS_TYPES      8
125 #define ah_trans2str(t)         \
126   ((t < NUM_AH_TRANS_TYPES) ? ah_transtypestr[t] : "UNKNOWN-AH-TRANS-TYPE")
127
128 static const char *ah_transtypestr[NUM_AH_TRANS_TYPES] = {
129   "RESERVED",
130   "RESERVED",
131   "MD5",
132   "SHA",
133   "DES",
134   "SHA2-256",
135   "SHA2-384",
136   "SHA2-512"
137 };
138
139 #define NUM_ESP_TRANS_TYPES     13
140 #define esp_trans2str(t)        \
141   ((t < NUM_ESP_TRANS_TYPES) ? esp_transtypestr[t] : "UNKNOWN-ESP-TRANS-TYPE")
142
143 static const char *esp_transtypestr[NUM_ESP_TRANS_TYPES] = {
144   "RESERVED",
145   "DES-IV64",
146   "DES",
147   "3DES",
148   "RC5",
149   "IDEA",
150   "CAST",
151   "BLOWFISH",
152   "3IDEA",
153   "DES-IV32",
154   "RC4",
155   "NULL",
156   "AES"
157 };
158
159 #define NUM_IPCOMP_TRANS_TYPES    5
160 #define ipcomp_trans2str(t)  \
161   ((t < NUM_IPCOMP_TRANS_TYPES) ? ipcomp_transtypestr[t] : "UNKNOWN-IPCOMP-TRANS-TYPE")
162
163 static const char *ipcomp_transtypestr[NUM_IPCOMP_TRANS_TYPES] = {
164   "RESERVED",
165   "OUI",
166   "DEFLATE",
167   "LZS",
168   "LZJH"
169 };
170
171 #define NUM_ID_TYPES    12
172 #define id2str(t)       \
173   ((t < NUM_ID_TYPES) ? idtypestr[t] : "UNKNOWN-ID-TYPE")
174
175 static const char *idtypestr[NUM_ID_TYPES] = {
176   "RESERVED",
177   "IPV4_ADDR",
178   "FQDN",
179   "USER_FQDN",
180   "IPV4_ADDR_SUBNET",
181   "IPV6_ADDR",
182   "IPV6_ADDR_SUBNET",
183   "IPV4_ADDR_RANGE",
184   "IPV6_ADDR_RANGE",
185   "DER_ASN1_DN",
186   "DER_ASN1_GN",
187   "KEY_ID"
188 };
189
190 struct isakmp_hdr {
191   guint8        icookie[8];
192   guint8        rcookie[8];
193   guint8        next_payload;
194   guint8        version;
195   guint8        exch_type;
196   guint8        flags;
197 #define E_FLAG          0x01
198 #define C_FLAG          0x02
199 #define A_FLAG          0x04
200   guint8        message_id[4];
201   guint8        length[4];
202 };
203
204 struct udp_encap_hdr {
205   guint8        non_ike_marker[8];
206   guint32       esp_SPI;
207 };
208
209 static proto_tree *dissect_payload_header(tvbuff_t *, int, int, guint8,
210     guint8 *, guint16 *, proto_tree *);
211
212 static void dissect_sa(tvbuff_t *, int, int, proto_tree *, int);
213 static void dissect_proposal(tvbuff_t *, int, int, proto_tree *, int);
214 static void dissect_transform(tvbuff_t *, int, int, proto_tree *, int);
215 static void dissect_key_exch(tvbuff_t *, int, int, proto_tree *, int);
216 static void dissect_id(tvbuff_t *, int, int, proto_tree *, int);
217 static void dissect_cert(tvbuff_t *, int, int, proto_tree *, int);
218 static void dissect_certreq(tvbuff_t *, int, int, proto_tree *, int);
219 static void dissect_hash(tvbuff_t *, int, int, proto_tree *, int);
220 static void dissect_sig(tvbuff_t *, int, int, proto_tree *, int);
221 static void dissect_nonce(tvbuff_t *, int, int, proto_tree *, int);
222 static void dissect_notif(tvbuff_t *, int, int, proto_tree *, int);
223 static void dissect_delete(tvbuff_t *, int, int, proto_tree *, int);
224 static void dissect_vid(tvbuff_t *, int, int, proto_tree *, int);
225 static void dissect_config(tvbuff_t *, int, int, proto_tree *, int);
226
227 static const char *payloadtype2str(guint8);
228 static const char *exchtype2str(guint8);
229 static const char *doitype2str(guint32);
230 static const char *msgtype2str(guint16);
231 static const char *situation2str(guint32);
232 static const char *value2str(int, guint16, guint16);
233 static const char *attrtype2str(guint8);
234 static const char *cfgattrident2str(guint16);
235 static const char *certtype2str(guint8);
236
237 static gboolean get_num(tvbuff_t *, int, guint16, guint32 *);
238
239 #define LOAD_TYPE_NONE          0       /* payload type for None */
240 #define LOAD_TYPE_PROPOSAL      2       /* payload type for Proposal */
241 #define LOAD_TYPE_TRANSFORM     3       /* payload type for Transform */
242 #define NUM_LOAD_TYPES          15
243 #define loadtype2str(t) \
244   ((t < NUM_LOAD_TYPES) ? strfuncs[t].str : "Unknown payload type")
245
246 static struct strfunc {
247   const char *  str;
248   void          (*func)(tvbuff_t *, int, int, proto_tree *, int);
249 } strfuncs[NUM_LOAD_TYPES] = {
250   {"NONE",                      NULL              },
251   {"Security Association",      dissect_sa        },
252   {"Proposal",                  dissect_proposal  },
253   {"Transform",                 dissect_transform },
254   {"Key Exchange",              dissect_key_exch  },
255   {"Identification",            dissect_id        },
256   {"Certificate",               dissect_cert      },
257   {"Certificate Request",       dissect_certreq   },
258   {"Hash",                      dissect_hash      },
259   {"Signature",                 dissect_sig       },
260   {"Nonce",                     dissect_nonce     },
261   {"Notification",              dissect_notif     },
262   {"Delete",                    dissect_delete    },
263   {"Vendor ID",                 dissect_vid       },
264   {"Attrib",                    dissect_config    }
265 };
266
267 static dissector_handle_t esp_handle;
268 static dissector_handle_t ah_handle;
269
270 static void
271 dissect_payloads(tvbuff_t *tvb, proto_tree *tree, guint8 initial_payload,
272                  int offset, int length)
273 {
274   guint8 payload, next_payload;
275   guint16               payload_length;
276   proto_tree *          ntree;
277
278   for (payload = initial_payload; length != 0; payload = next_payload) {
279     if (payload == LOAD_TYPE_NONE) {
280       /*
281        * What?  There's more stuff in this chunk of data, but the
282        * previous payload had a "next payload" type of None?
283        */
284       proto_tree_add_text(tree, tvb, offset, length,
285                           "Extra data: %s",
286                           tvb_bytes_to_str(tvb, offset, length));
287       break;
288     }
289     ntree = dissect_payload_header(tvb, offset, length, payload,
290       &next_payload, &payload_length, tree);
291     if (ntree == NULL)
292       break;
293     if (payload_length >= 4) {  /* XXX = > 4? */
294       if (payload < NUM_LOAD_TYPES) {
295         (*strfuncs[payload].func)(tvb, offset + 4, payload_length - 4, ntree,
296                                   -1);
297       }
298       else {
299         proto_tree_add_text(ntree, tvb, offset + 4, payload_length - 4,
300             "Payload");
301       }
302     }
303     else {
304         proto_tree_add_text(ntree, tvb, offset + 4, 0,
305             "Payload (bogus, length is %u, must be at least 4)",
306             payload_length);
307         payload_length = 4;
308     }
309     offset += payload_length;
310     length -= payload_length;
311   }
312 }
313
314 static void
315 dissect_isakmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
316 {
317   int                   offset = 0;
318   struct isakmp_hdr *   hdr;
319   proto_item *          ti;
320   proto_tree *          isakmp_tree = NULL;
321   struct udp_encap_hdr * encap_hdr;
322   guint32               len;
323   static const guint8   non_ike_marker[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
324   tvbuff_t *            next_tvb;
325
326   if (check_col(pinfo->cinfo, COL_PROTOCOL))
327     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISAKMP");
328   if (check_col(pinfo->cinfo, COL_INFO))
329     col_clear(pinfo->cinfo, COL_INFO);
330
331   hdr = (struct isakmp_hdr *)tvb_get_ptr(tvb, 0, sizeof (struct isakmp_hdr));
332   len = pntohl(&hdr->length);
333   
334   if (tree) {
335     ti = proto_tree_add_item(tree, proto_isakmp, tvb, offset, len, FALSE);
336     isakmp_tree = proto_item_add_subtree(ti, ett_isakmp);
337   }
338     
339   encap_hdr = (struct udp_encap_hdr *)tvb_get_ptr(tvb, 0, sizeof(struct udp_encap_hdr));
340   
341   if (encap_hdr->non_ike_marker[0] == 0xFF) {
342     if (check_col(pinfo->cinfo, COL_INFO)) 
343       col_set_str(pinfo->cinfo, COL_INFO, "UDP encapsulated IPSec - NAT Keepalive");
344     return;
345   }
346   if (memcmp(encap_hdr->non_ike_marker,non_ike_marker,8) == 0) {
347     if (check_col(pinfo->cinfo, COL_INFO)) {
348       if (encap_hdr->esp_SPI != 0)
349           col_set_str(pinfo->cinfo, COL_INFO, "UDP encapsulated IPSec - ESP");
350       else
351          col_set_str(pinfo->cinfo, COL_INFO, "UDP encapsulated IPSec - AH");
352     } 
353     if (tree)
354       proto_tree_add_text(isakmp_tree, tvb, offset,
355                           sizeof(encap_hdr->non_ike_marker),
356                           "Non-IKE-Marker");
357     offset += sizeof(encap_hdr->non_ike_marker);
358       
359     if (encap_hdr->esp_SPI != 0) {
360       next_tvb = tvb_new_subset(tvb, offset, -1, -1);
361       call_dissector(esp_handle, next_tvb, pinfo, tree);
362     } else {
363       if (tree)
364         proto_tree_add_text(isakmp_tree, tvb, offset,
365                             sizeof(encap_hdr->esp_SPI),
366                             "Non-ESP-Marker");
367       offset += sizeof(encap_hdr->esp_SPI);
368
369       if (tree)
370         proto_tree_add_text(isakmp_tree, tvb, offset, 1,
371                             "AH Envelope Version: %u",
372                             tvb_get_guint8(tvb, offset) >> 4);
373       offset += 1;
374
375       if (tree)
376         proto_tree_add_text(isakmp_tree, tvb, offset, 1,
377                             "AH Envelope Header Length: %u",
378                             (tvb_get_guint8(tvb, offset) & 0xF)*4);
379       offset += 1;
380
381       if (tree)
382         proto_tree_add_text(isakmp_tree, tvb, offset, 2,
383                             "AH Envelope Identification: 0x%04X",
384                             tvb_get_ntohs(tvb, offset));
385       offset += 2;
386
387       next_tvb = tvb_new_subset(tvb, offset, -1, -1);
388       call_dissector(ah_handle, next_tvb, pinfo, tree);
389     }
390     return;
391   }
392
393   if (check_col(pinfo->cinfo, COL_INFO))
394     col_add_str(pinfo->cinfo, COL_INFO, exchtype2str(hdr->exch_type));
395
396   if (tree) {
397     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->icookie),
398                         "Initiator cookie");
399     offset += sizeof(hdr->icookie);
400     
401     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->rcookie),
402                         "Responder cookie");
403     offset += sizeof(hdr->rcookie);
404
405     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->next_payload),
406                         "Next payload: %s (%u)",
407                         payloadtype2str(hdr->next_payload), hdr->next_payload);
408     offset += sizeof(hdr->next_payload);
409
410     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->version),
411                         "Version: %u.%u",
412                         hi_nibble(hdr->version), lo_nibble(hdr->version));
413     offset += sizeof(hdr->version);
414     
415     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->exch_type),
416                         "Exchange type: %s (%u)",
417                         exchtype2str(hdr->exch_type), hdr->exch_type);
418     offset += sizeof(hdr->exch_type);
419     
420     {
421       proto_item *      fti;
422       proto_tree *      ftree;
423       
424       fti   = proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->flags), "Flags");
425       ftree = proto_item_add_subtree(fti, ett_isakmp_flags);
426       
427       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
428                           decode_boolean_bitfield(hdr->flags, E_FLAG, sizeof(hdr->flags)*8,
429                                                   "Encryption", "No encryption"));
430       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
431                           decode_boolean_bitfield(hdr->flags, C_FLAG, sizeof(hdr->flags)*8,
432                                                   "Commit", "No commit"));
433       proto_tree_add_text(ftree, tvb, offset, 1, "%s",
434                           decode_boolean_bitfield(hdr->flags, A_FLAG, sizeof(hdr->flags)*8,
435                                                   "Authentication", "No authentication"));
436       offset += sizeof(hdr->flags);
437     }
438
439     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->message_id),
440         "Message ID: 0x%02x%02x%02x%02x", hdr->message_id[0],
441         hdr->message_id[1], hdr->message_id[2], hdr->message_id[3]);
442     offset += sizeof(hdr->message_id);
443     
444     proto_tree_add_text(isakmp_tree, tvb, offset, sizeof(hdr->length),
445                         "Length: %u", len);
446     offset += sizeof(hdr->length);
447     len -= sizeof(*hdr);
448
449     if (hdr->flags & E_FLAG) {
450       if (len && isakmp_tree) {
451         proto_tree_add_text(isakmp_tree, tvb, offset, len,
452                         "Encrypted payload (%d byte%s)",
453                         len, plurality(len, "", "s"));
454       }
455     } else
456       dissect_payloads(tvb, isakmp_tree, hdr->next_payload, offset, len);
457   }
458 }
459
460 static proto_tree *
461 dissect_payload_header(tvbuff_t *tvb, int offset, int length, guint8 payload,
462     guint8 *next_payload_p, guint16 *payload_length_p, proto_tree *tree)
463 {
464   guint8                next_payload;
465   guint16               payload_length;
466   proto_item *          ti;
467   proto_tree *          ntree;
468
469   if (length < 4) {
470     proto_tree_add_text(tree, tvb, offset, length,
471           "Not enough room in payload for all transforms");
472     return NULL;
473   }
474   next_payload = tvb_get_guint8(tvb, offset);
475   payload_length = tvb_get_ntohs(tvb, offset + 2);
476
477   ti = proto_tree_add_text(tree, tvb, offset, payload_length,
478             "%s payload", loadtype2str(payload));
479   ntree = proto_item_add_subtree(ti, ett_isakmp_payload);
480
481   proto_tree_add_text(ntree, tvb, offset, 1,
482                       "Next payload: %s (%u)",
483                       payloadtype2str(next_payload), next_payload);
484   proto_tree_add_text(ntree, tvb, offset+2, 2, "Length: %u", payload_length);
485
486   *next_payload_p = next_payload;
487   *payload_length_p = payload_length;
488   return ntree;
489 }
490
491 static void
492 dissect_sa(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
493     int unused)
494 {
495   guint32               doi;
496   guint32               situation;
497
498   if (length < 4) {
499     proto_tree_add_text(tree, tvb, offset, length,
500                         "DOI %s (length is %u, should be >= 4)",
501                         tvb_bytes_to_str(tvb, offset, length), length);
502     return;
503   }
504   doi = tvb_get_ntohl(tvb, offset);
505   proto_tree_add_text(tree, tvb, offset, 4,
506                       "Domain of interpretation: %s (%u)",
507                       doitype2str(doi), doi);
508   offset += 4;
509   length -= 4;
510   
511   if (doi == 1) {
512     /* IPSEC */
513     if (length < 4) {
514       proto_tree_add_text(tree, tvb, offset, length,
515                           "Situation: %s (length is %u, should be >= 4)",
516                           tvb_bytes_to_str(tvb, offset, length), length);
517       return;
518     }
519     situation = tvb_get_ntohl(tvb, offset);
520     proto_tree_add_text(tree, tvb, offset, 4,
521                         "Situation: %s (%u)",
522                         situation2str(situation), situation);
523     offset += 4;
524     length -= 4;
525   
526     dissect_payloads(tvb, tree, LOAD_TYPE_PROPOSAL, offset, length);
527   } else {
528     /* Unknown */
529     proto_tree_add_text(tree, tvb, offset, length,
530                         "Situation: %s",
531                         tvb_bytes_to_str(tvb, offset, length));
532   }
533 }
534
535 static void
536 dissect_proposal(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
537     int unused)
538 {
539   guint8                protocol_id;
540   guint8                spi_size;
541   guint8                num_transforms;
542   guint8                next_payload;
543   guint16               payload_length;
544   proto_tree *          ntree;
545
546   proto_tree_add_text(tree, tvb, offset, 1,
547                       "Proposal number: %u", tvb_get_guint8(tvb, offset));
548   offset += 1;
549   length -= 1;
550   
551   protocol_id = tvb_get_guint8(tvb, offset);
552   proto_tree_add_text(tree, tvb, offset, 1,
553                       "Protocol ID: %s (%u)",
554                       proto2str(protocol_id), protocol_id);
555   offset += 1;
556   length -= 1;
557   
558   spi_size = tvb_get_guint8(tvb, offset);
559   proto_tree_add_text(tree, tvb, offset, 1,
560                       "SPI size: %u", spi_size);
561   offset += 1;
562   length -= 1;
563
564   num_transforms = tvb_get_guint8(tvb, offset);
565   proto_tree_add_text(tree, tvb, offset, 1,
566                       "Number of transforms: %u", num_transforms);
567   offset += 1;
568   length -= 1;
569
570   if (spi_size) {
571     proto_tree_add_text(tree, tvb, offset, spi_size, "SPI: %s",
572                         tvb_bytes_to_str(tvb, offset, spi_size));
573     offset += spi_size;
574     length -= spi_size;
575   }
576
577   while (num_transforms > 0) {
578     ntree = dissect_payload_header(tvb, offset, length, LOAD_TYPE_TRANSFORM,
579       &next_payload, &payload_length, tree);
580     if (ntree == NULL)
581       break;
582     if (length < payload_length) {
583       proto_tree_add_text(tree, tvb, offset + 4, length,
584           "Not enough room in payload for all transforms");
585       break;
586     }
587     if (payload_length >= 4)
588       dissect_transform(tvb, offset + 4, payload_length - 4, ntree, protocol_id);
589     else
590       proto_tree_add_text(ntree, tvb, offset + 4, payload_length - 4, "Payload");
591     offset += payload_length;
592     length -= payload_length;
593     num_transforms--;
594   }
595 }
596
597 static void
598 dissect_transform(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
599     int protocol_id)
600 {
601   guint8                transform_id;
602
603   proto_tree_add_text(tree, tvb, offset, 1,
604                       "Transform number: %u", tvb_get_guint8(tvb, offset));
605   offset += 1;
606   length -= 1;
607
608   transform_id = tvb_get_guint8(tvb, offset);
609   switch (protocol_id) {
610   default:
611     proto_tree_add_text(tree, tvb, offset, 1,
612                         "Transform ID: %u", transform_id);
613     break;
614   case 1:       /* ISAKMP */
615     proto_tree_add_text(tree, tvb, offset, 1,
616                         "Transform ID: %s (%u)",
617                         trans2str(transform_id), transform_id);
618     break;
619   case 2:       /* AH */
620     proto_tree_add_text(tree, tvb, offset, 1,
621                         "Transform ID: %s (%u)",
622                         ah_trans2str(transform_id), transform_id);
623     break;
624   case 3:       /* ESP */
625     proto_tree_add_text(tree, tvb, offset, 1,
626                         "Transform ID: %s (%u)",
627                         esp_trans2str(transform_id), transform_id);
628     break;
629   case 4:       /* IPCOMP */
630     proto_tree_add_text(tree, tvb, offset, 1,
631                         "Transform ID: %s (%u)",
632                         ipcomp_trans2str(transform_id), transform_id);
633     break;
634   }
635   offset += 3;
636   length -= 3;
637   
638   while (length>0) {
639     const char *str;
640     int ike_phase1 = 0;
641     guint16 aft     = tvb_get_ntohs(tvb, offset);
642     guint16 type    = aft & 0x7fff;
643     guint16 len;
644     guint32 val;
645     guint pack_len;
646
647     if (protocol_id == 1 && transform_id == 1) {
648       ike_phase1 = 1;
649       str = p1_atttype2str(type);
650     }
651     else {
652       str = atttype2str(type);
653     }
654
655     if (aft & 0x8000) {
656       val = tvb_get_ntohs(tvb, offset + 2);
657       proto_tree_add_text(tree, tvb, offset, 4,
658                           "%s (%u): %s (%u)",
659                           str, type,
660                           value2str(ike_phase1, type, val), val);
661       offset += 4;
662       length -= 4;
663     }
664     else {
665       len = tvb_get_ntohs(tvb, offset + 2);
666       pack_len = 4 + len;
667       if (!get_num(tvb, offset + 4, len, &val)) {
668         proto_tree_add_text(tree, tvb, offset, pack_len,
669                             "%s (%u): <too big (%u bytes)>",
670                             str, type, len);
671       } else {
672         proto_tree_add_text(tree, tvb, offset, pack_len,
673                             "%s (%u): %s (%u)",
674                             str, type,
675                             value2str(ike_phase1, type, val), val);
676       }
677       offset += pack_len;
678       length -= pack_len;
679     }
680   }
681 }
682
683 static void
684 dissect_key_exch(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
685     int unused)
686 {
687   proto_tree_add_text(tree, tvb, offset, length, "Key Exchange Data");
688 }
689
690 static void
691 dissect_id(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
692     int unused)
693 {
694   guint8                id_type;
695   guint8                protocol_id;
696   guint16               port;
697
698   id_type = tvb_get_guint8(tvb, offset);
699   proto_tree_add_text(tree, tvb, offset, 1,
700                       "ID type: %s (%u)", id2str(id_type), id_type);
701   offset += 1;
702   length -= 1;
703
704   protocol_id = tvb_get_guint8(tvb, offset);
705   if (protocol_id == 0) {
706     proto_tree_add_text(tree, tvb, offset, 1,
707                         "Protocol ID: Unused");
708   } else {
709     proto_tree_add_text(tree, tvb, offset, 1,
710                         "Protocol ID: %s (%u)",
711                         ipprotostr(protocol_id), protocol_id);
712   }
713   offset += 1;
714   length -= 1;
715
716   port = tvb_get_ntohs(tvb, offset);
717   if (port == 0)
718     proto_tree_add_text(tree, tvb, offset, 2, "Port: Unused");
719   else
720     proto_tree_add_text(tree, tvb, offset, 2, "Port: %u", port);
721   offset += 2;
722   length -= 2;
723   
724   switch (id_type) {
725     case 1:
726       proto_tree_add_text(tree, tvb, offset, length,
727                           "Identification data: %s",
728                           ip_to_str(tvb_get_ptr(tvb, offset, 4)));
729       break;
730     case 2:
731     case 3:
732       proto_tree_add_text(tree, tvb, offset, length,
733                           "Identification data: %.*s", length,
734                           tvb_get_ptr(tvb, offset, length));
735       break;
736     case 4:
737       proto_tree_add_text(tree, tvb, offset, length,
738                           "Identification data: %s/%s",
739                           ip_to_str(tvb_get_ptr(tvb, offset, 4)),
740                           ip_to_str(tvb_get_ptr(tvb, offset+4, 4)));
741       break;
742     default:
743       proto_tree_add_text(tree, tvb, offset, length, "Identification Data");
744       break;
745   }
746 }
747
748 static void
749 dissect_cert(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
750     int unused)
751 {
752   guint8                cert_enc;
753
754   cert_enc = tvb_get_guint8(tvb, offset);
755   proto_tree_add_text(tree, tvb, offset, 1,
756                       "Certificate encoding: %u - %s",
757                       cert_enc, certtype2str(cert_enc));
758   offset += 1;
759   length -= 1;
760
761   proto_tree_add_text(tree, tvb, offset, length, "Certificate Data");
762 }
763
764 static void
765 dissect_certreq(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
766     int unused)
767 {
768   guint8                cert_type;
769
770   cert_type = tvb_get_guint8(tvb, offset);
771   proto_tree_add_text(tree, tvb, offset, 1,
772                       "Certificate type: %u - %s",
773                       cert_type, certtype2str(cert_type));
774   offset += 1;
775   length -= 1;
776
777   proto_tree_add_text(tree, tvb, offset, length, "Certificate Authority");
778 }
779
780 static void
781 dissect_hash(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
782     int unused)
783 {
784   proto_tree_add_text(tree, tvb, offset, length, "Hash Data");
785 }
786
787 static void
788 dissect_sig(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
789     int unused)
790 {
791   proto_tree_add_text(tree, tvb, offset, length, "Signature Data");
792 }
793
794 static void
795 dissect_nonce(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
796     int unused)
797 {
798   proto_tree_add_text(tree, tvb, offset, length, "Nonce Data");
799 }
800
801 static void
802 dissect_notif(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
803     int unused)
804 {
805   guint32               doi;
806   guint8                protocol_id;
807   guint8                spi_size;
808   guint16               msgtype;
809
810   doi = tvb_get_ntohl(tvb, offset);
811   proto_tree_add_text(tree, tvb, offset, 4,
812                       "Domain of Interpretation: %s (%u)",
813                       doitype2str(doi), doi);
814   offset += 4;
815   length -= 4;
816
817   protocol_id = tvb_get_guint8(tvb, offset);
818   proto_tree_add_text(tree, tvb, offset, 1,
819                       "Protocol ID: %s (%u)",
820                       proto2str(protocol_id), protocol_id);
821   offset += 1;
822   length -= 1;
823   
824   spi_size = tvb_get_guint8(tvb, offset);
825   proto_tree_add_text(tree, tvb, offset, 1,
826                       "SPI size: %u", spi_size);
827   offset += 1;
828   length -= 1;
829   
830   msgtype = tvb_get_ntohs(tvb, offset);
831   proto_tree_add_text(tree, tvb, offset, 2,
832                       "Message type: %s (%u)", msgtype2str(msgtype), msgtype);
833   offset += 2;
834   length -= 2;
835
836   if (spi_size) {
837     proto_tree_add_text(tree, tvb, offset, spi_size, "Security Parameter Index");
838     offset += spi_size;
839     length -= spi_size;
840   }
841
842   if (length > 0)
843     proto_tree_add_text(tree, tvb, offset, length, "Notification Data");
844 }
845
846 static void
847 dissect_delete(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
848     int unused)
849 {
850   guint32               doi;
851   guint8                protocol_id;
852   guint8                spi_size;
853   guint16               num_spis;
854   guint16               i;
855   
856   doi = tvb_get_ntohl(tvb, offset);
857   proto_tree_add_text(tree, tvb, offset, 4,
858                       "Domain of Interpretation: %s (%u)",
859                       doitype2str(doi), doi);
860   offset += 4;
861   length -= 4;
862
863   protocol_id = tvb_get_guint8(tvb, offset);
864   proto_tree_add_text(tree, tvb, offset, 1,
865                       "Protocol ID: %s (%u)",
866                       proto2str(protocol_id), protocol_id);
867   offset += 1;
868   length -= 1;
869   
870   spi_size = tvb_get_guint8(tvb, offset);
871   proto_tree_add_text(tree, tvb, offset, 1,
872                       "SPI size: %u", spi_size);
873   offset += 1;
874   length -= 1;
875
876   num_spis = tvb_get_ntohs(tvb, offset);
877   proto_tree_add_text(tree, tvb, offset, 2,
878                       "Number of SPIs: %u", num_spis);
879   offset += 2;
880   length -= 2;
881   
882   for (i = 0; i < num_spis; ++i) {
883     if (length < spi_size) {
884       proto_tree_add_text(tree, tvb, offset, length,
885           "Not enough room in payload for all SPI's");
886       break;
887     }
888     proto_tree_add_text(tree, tvb, offset, spi_size,
889                         "SPI (%d)", i);
890     offset += spi_size;
891     length -= spi_size;
892   }
893 }
894
895 static void
896 dissect_vid(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
897     int unused)
898 {
899   proto_tree_add_text(tree, tvb, offset, length, "Vendor ID");
900 }
901
902 static void
903 dissect_config(tvbuff_t *tvb, int offset, int length, proto_tree *tree,
904     int unused)
905 {
906   guint8                type;
907
908   type = tvb_get_guint8(tvb, offset);
909   proto_tree_add_text(tree, tvb, offset, 1,
910                       "Type %s (%u)",attrtype2str(type),type);
911   
912   offset += 2;
913   length -= 2;
914   
915   proto_tree_add_text(tree, tvb, offset, 2,
916                       "Identifier: %u", tvb_get_ntohs(tvb, offset));
917   offset += 2;
918   length -= 2;
919   
920   while(length>0) {
921     guint16 aft     = tvb_get_ntohs(tvb, offset);
922     guint16 type    = aft & 0x7fff;
923     guint16 len;
924     guint32 val;
925     guint pack_len;
926
927     if (aft & 0x8000) {
928       val = tvb_get_ntohs(tvb, offset + 2);
929       proto_tree_add_text(tree, tvb, offset, 4,
930                           "%s (%u)", cfgattrident2str(type), val);
931       offset += 4;
932       length -= 4;
933     }
934     else {
935       len = tvb_get_ntohs(tvb, offset + 2);
936       pack_len = 4 + len;
937       if (!get_num(tvb, offset + 4, len, &val)) {
938         proto_tree_add_text(tree, tvb, offset, pack_len,
939                             "%s: <too big (%u bytes)>",
940                             cfgattrident2str(type), len);
941       } else {
942         proto_tree_add_text(tree, tvb, offset, 4,
943                             "%s (%ue)", cfgattrident2str(type),
944                             val);
945       }
946       offset += pack_len;
947       length -= pack_len;
948     }
949   }
950 }
951
952 static const char *
953 payloadtype2str(guint8 type) {
954
955   if (type < NUM_LOAD_TYPES) return strfuncs[type].str;
956   if (type < 128)            return "RESERVED";
957   if (type < 256)            return "Private USE";
958
959   return "Huh? You should never see this! Shame on you!";
960 }
961
962 static const char *
963 exchtype2str(guint8 type) {
964
965 #define NUM_EXCHSTRS    7
966   static const char * exchstrs[NUM_EXCHSTRS] = {
967     "NONE",
968     "Base",
969     "Identity Protection (Main Mode)",
970     "Authentication Only",
971     "Aggressive",
972     "Informational",
973     "Transaction (Config Mode)"
974   };
975   
976   if (type < NUM_EXCHSTRS) return exchstrs[type];
977   if (type < 32)           return "ISAKMP Future Use";
978   switch (type) {
979   case 32:
980     return "Quick Mode";
981   case 33:
982     return "New Group Mode";
983   }
984   if (type < 240)          return "DOI Specific Use";
985   if (type < 256)          return "Private Use";
986   
987   return "Huh? You should never see this! Shame on you!";
988 }
989
990 static const char *
991 doitype2str(guint32 type) {
992   if (type == 1) return "IPSEC";
993   return "Unknown DOI Type";
994 }
995
996 static const char *
997 msgtype2str(guint16 type) {
998
999 #define NUM_PREDEFINED  31
1000   static const char *msgs[NUM_PREDEFINED] = {
1001     "<UNKNOWN>",
1002     "INVALID-PAYLOAD-TYPE",
1003     "DOI-NOT-SUPPORTED",
1004     "SITUATION-NOT-SUPPORTED",
1005     "INVALID-COOKIE",
1006     "INVALID-MAJOR-VERSION",
1007     "INVALID-MINOR-VERSION",
1008     "INVALID-EXCHANGE-TYPE",
1009     "INVALID-FLAGS",
1010     "INVALID-MESSAGE-ID",
1011     "INVALID-PROTOCOL-ID",
1012     "INVALID-SPI",
1013     "INVALID-TRANSFORM-ID",
1014     "ATTRIBUTES-NOT-SUPPORTED",
1015     "NO-PROPOSAL-CHOSEN",
1016     "BAD-PROPOSAL-SYNTAX",
1017     "PAYLOAD-MALFORMED",
1018     "INVALID-KEY-INFORMATION",
1019     "INVALID-ID-INFORMATION",
1020     "INVALID-CERT-ENCODING",
1021     "INVALID-CERTIFICATE",
1022     "CERT-TYPE-UNSUPPORTED",
1023     "INVALID-CERT-AUTHORITY",
1024     "INVALID-HASH-INFORMATION",
1025     "AUTHENTICATION-FAILED",
1026     "INVALID-SIGNATURE",
1027     "ADDRESS-NOTIFICATION",
1028     "NOTIFY-SA-LIFETIME",
1029     "CERTIFICATE-UNAVAILABLE",
1030     "UNSUPPORTED-EXCHANGE-TYPE",
1031     "UNEQUAL-PAYLOAD-LENGTHS"
1032   };
1033
1034   if (type < NUM_PREDEFINED) return msgs[type];
1035   if (type < 8192)           return "RESERVED (Future Use)";
1036   if (type < 16384)          return "Private Use";
1037   if (type < 16385)          return "CONNECTED";
1038   if (type < 24576)          return "RESERVED (Future Use) - status";
1039   if (type < 24577)          return "RESPONDER-LIFETIME";
1040   if (type < 24578)          return "REPLAY-STATUS";
1041   if (type < 24579)          return "INITIAL-CONTACT";
1042   if (type < 32768)          return "DOI-specific codes";
1043   if (type < 40960)          return "Private Use - status";
1044   if (type < 65535)          return "RESERVED (Future Use) - status (2)";
1045
1046   return "Huh? You should never see this! Shame on you!";
1047 }
1048
1049 static const char *
1050 situation2str(guint32 type) {
1051
1052 #define SIT_MSG_NUM     1024
1053 #define SIT_IDENTITY    0x01
1054 #define SIT_SECRECY     0x02
1055 #define SIT_INTEGRITY   0x04
1056
1057   static char   msg[SIT_MSG_NUM];
1058   int           n = 0;
1059   char *        sep = "";
1060   int           ret;
1061   
1062   if (type & SIT_IDENTITY) {
1063     ret = snprintf(msg, SIT_MSG_NUM-n, "%sIDENTITY", sep);
1064     if (ret == -1) {
1065       /* Some versions of snprintf return -1 if they'd truncate the output. */
1066       return msg;
1067     }
1068     n += ret;
1069     sep = " & ";
1070   }
1071   if (type & SIT_SECRECY) {
1072     if (n >= SIT_MSG_NUM) {
1073       /* No more room. */
1074       return msg;
1075     }
1076     ret = snprintf(msg, SIT_MSG_NUM-n, "%sSECRECY", sep);
1077     if (ret == -1) {
1078       /* Some versions of snprintf return -1 if they'd truncate the output. */
1079       return msg;
1080     }
1081     n += ret;
1082     sep = " & ";
1083   }
1084   if (type & SIT_INTEGRITY) {
1085     if (n >= SIT_MSG_NUM) {
1086       /* No more room. */
1087       return msg;
1088     }
1089     ret = snprintf(msg, SIT_MSG_NUM-n, "%sINTEGRITY", sep);
1090     if (ret == -1) {
1091       /* Some versions of snprintf return -1 if they'd truncate the output. */
1092       return msg;
1093     }
1094     n += ret;
1095     sep = " & ";
1096   }
1097
1098   return msg;
1099 }
1100
1101 static const char *
1102 value2str(int ike_p1, guint16 att_type, guint16 value) {
1103   
1104   if (value == 0) return "RESERVED";
1105   
1106   if (!ike_p1) {
1107   switch (att_type) {
1108     case 1:
1109       switch (value) {
1110         case 1:  return "Seconds";
1111         case 2:  return "Kilobytes";
1112         default: return "UNKNOWN-SA-VALUE";
1113       }
1114     case 2:
1115       return "Duration-Value";
1116     case 3:
1117       return "Group-Value";
1118     case 4:
1119       switch (value) {
1120         case 1:  return "Tunnel";
1121         case 2:  return "Transport";
1122         case 61440: return "Check Point IPSec UDP Encapsulation";
1123         case 61443: return "UDP-Encapsulated-Tunnel (draft)";
1124         case 61444: return "UDP-Encapsulated-Transport (draft)";
1125         default: return "UNKNOWN-ENCAPSULATION-VALUE";
1126       }
1127     case 5:
1128       switch (value) {
1129         case 1:  return "HMAC-MD5";
1130         case 2:  return "HMAC-SHA";
1131         case 3:  return "DES-MAC";
1132         case 4:  return "KPDK";
1133         case 5:  return "HMAC-SHA2-256";
1134         case 6:  return "HMAC-SHA2-384";
1135         case 7:  return "HMAC-SHA2-512";
1136         default: return "UNKNOWN-AUTHENTICATION-VALUE";
1137       }
1138     case 6:
1139       return "Key-Length";
1140     case 7:
1141       return "Key-Rounds";
1142     case 8:
1143       return "log2-size";
1144     default: return "UNKNOWN-ATTRIBUTE-TYPE";
1145   }
1146   }
1147   else {
1148     switch (att_type) {
1149       case 1:
1150         switch (value) {
1151           case 1:  return "DES-CBC";
1152           case 2:  return "IDEA-CBC";
1153           case 3:  return "BLOWFISH-CBC";
1154           case 4:  return "RC5-R16-B64-CBC";
1155           case 5:  return "3DES-CBC";
1156           case 6:  return "CAST-CBC";
1157           case 7:  return "AES-CBC";
1158           default: return "UNKNOWN-ENCRYPTION-ALG";
1159         }
1160       case 2:
1161         switch (value) {
1162           case 1:  return "MD5";
1163           case 2:  return "SHA";
1164           case 3:  return "TIGER";
1165           case 4:  return "SHA2-256";
1166           case 5:  return "SHA2-384";
1167           case 6:  return "SHA2-512";
1168           default: return "UNKNOWN-HASH-ALG";
1169         }
1170       case 3:
1171         switch (value) {
1172           case 1:  return "PSK";
1173           case 2:  return "DSS-SIG";
1174           case 3:  return "RSA-SIG";
1175           case 4:  return "RSA-ENC";
1176           case 5:  return "RSA-Revised-ENC";
1177           case 64221: return "HybridInitRSA";
1178           case 64222: return "HybridRespRSA";
1179           case 64223: return "HybridInitDSS";
1180           case 64224: return "HybridRespDSS";
1181           case 65001: return "XAUTHInitPreShared";
1182           case 65002: return "XAUTHRespPreShared";
1183           case 65003: return "XAUTHInitDSS";
1184           case 65004: return "XAUTHRespDSS";
1185           case 65005: return "XAUTHInitRSA";
1186           case 65006: return "XAUTHRespRSA";
1187           case 65007: return "XAUTHInitRSAEncryption";
1188           case 65008: return "XAUTHRespRSAEncryption";
1189           case 65009: return "XAUTHInitRSARevisedEncryption";
1190           case 65010: return "XAUTHRespRSARevisedEncryption";
1191           default: return "UNKNOWN-AUTH-METHOD";
1192         }
1193       case 4:
1194       case 6:
1195       case 7:
1196       case 8:
1197       case 9:
1198       case 10:
1199       case 16:
1200         return "Group-Value";
1201       case 5:
1202         switch (value) {
1203           case 1:  return "MODP";
1204           case 2:  return "ECP";
1205           case 3:  return "EC2N";
1206           default: return "UNKNOWN-GROUPT-TYPE";
1207         }
1208       case 11:
1209         switch (value) {
1210           case 1:  return "Seconds";
1211           case 2:  return "Kilobytes";
1212           default: return "UNKNOWN-SA-VALUE";
1213         }
1214       case 12:
1215         return "Duration-Value";
1216       case 13:
1217         return "PRF-Value";
1218       case 14:
1219         return "Key-Length";
1220       case 15:
1221         return "Field-Size";
1222       default: return "UNKNOWN-ATTRIBUTE-TYPE";
1223     }
1224   }
1225 }
1226
1227 static const char * 
1228 attrtype2str(guint8 type) {
1229   switch (type) {
1230   case 0: return "Reserved";
1231   case 1: return "ISAKMP_CFG_REQUEST";
1232   case 2: return "ISAKMP_CFG_REPLY";
1233   case 3: return "ISAKMP_CFG_SET";
1234   case 4: return "ISAKMP_CFG_ACK";
1235   }
1236   if(type < 127)
1237     return "Future use";
1238   return "Private use";
1239 }
1240
1241 static const char * 
1242 cfgattrident2str(guint16 ident) {
1243 #define NUM_ATTR_DEFINED        12
1244   static const char *msgs[NUM_PREDEFINED] = {
1245     "RESERVED",
1246     "INTERNAL_IP4_ADDRESS",
1247     "INTERNAL_IP4_NETMASK",
1248     "INTERNAL_IP4_DNS",
1249     "INTERNAL_IP4_NBNS",
1250     "INTERNAL_ADDRESS_EXPIREY",
1251     "INTERNAL_IP4_DHCP",
1252     "APPLICATION_VERSION"
1253     "INTERNAL_IP6_ADDRESS",
1254     "INTERNAL_IP6_NETMASK",
1255     "INTERNAL_IP6_DNS",
1256     "INTERNAL_IP6_NBNS",
1257     "INTERNAL_IP6_DHCP",
1258   }; 
1259   if(ident < NUM_ATTR_DEFINED)
1260     return msgs[ident];
1261   if(ident < 16383)
1262     return "Future use";
1263   switch(ident) {
1264   case 16520: return "XAUTH_TYPE";
1265   case 16521: return "XAUTH_USER_NAME";
1266   case 16522: return "XAUTH_USER_PASSWORD";
1267   case 16523: return "XAUTH_PASSCODE";
1268   case 16524: return "XAUTH_MESSAGE";
1269   case 16525: return "XAUTH_CHALLANGE";
1270   case 16526: return "XAUTH_DOMAIN";
1271   case 16527: return "XAUTH_STATUS";
1272   case 16528: return "XAUTH_NEXT_PIN";
1273   case 16529: return "XAUTH_ANSWER";
1274   default: return "Private use";
1275   }
1276 }
1277
1278 static const char *
1279 certtype2str(guint8 type) {
1280 #define NUM_CERTTYPE 11
1281   static const char *msgs[NUM_CERTTYPE] = {
1282     "NONE",
1283     "PKCS #7 wrapped X.509 certificate",
1284     "PGP Certificate",
1285     "DNS Signed Key",
1286     "X.509 Certificate - Signature",
1287     "X.509 Certificate - Key Exchange",
1288     "Kerberos Tokens",
1289     "Certificate Revocation List (CRL)",
1290     "Authority Revocation List (ARL)",
1291     "SPKI Certificate",
1292     "X.509 Certificate - Attribute",
1293   };
1294   if(type > NUM_CERTTYPE)
1295     return "RESERVED";
1296   return msgs[type];
1297 }
1298
1299 static gboolean
1300 get_num(tvbuff_t *tvb, int offset, guint16 len, guint32 *num_p) {
1301
1302   switch (len) {
1303   case 1:
1304     *num_p = tvb_get_guint8(tvb, offset);
1305     break;
1306   case 2:
1307     *num_p = tvb_get_ntohs(tvb, offset);
1308     break;
1309   case 3:
1310     *num_p = tvb_get_ntoh24(tvb, offset);
1311     break;
1312   case 4:
1313     *num_p = tvb_get_ntohl(tvb, offset);
1314     break;
1315   default:
1316     return FALSE;
1317   }
1318
1319   return TRUE;
1320 }
1321
1322 void
1323 proto_register_isakmp(void)
1324 {
1325 /*  static hf_register_info hf[] = {
1326     { &variable,
1327     { "Name",           "isakmp.abbreviation", TYPE, VALS_POINTER }},
1328   };*/
1329   static gint *ett[] = {
1330     &ett_isakmp,
1331     &ett_isakmp_flags,
1332     &ett_isakmp_payload,
1333   };
1334
1335   proto_isakmp = proto_register_protocol("Internet Security Association and Key Management Protocol",
1336                                                "ISAKMP", "isakmp");
1337 /*  proto_register_field_array(proto_isakmp, hf, array_length(hf));*/
1338   proto_register_subtree_array(ett, array_length(ett));
1339 }
1340
1341 void
1342 proto_reg_handoff_isakmp(void)
1343 {
1344   dissector_handle_t isakmp_handle;
1345
1346   /*
1347    * Get handle for the AH & ESP dissectors.
1348    */
1349   esp_handle = find_dissector("esp");
1350   ah_handle = find_dissector("ah");
1351
1352   isakmp_handle = create_dissector_handle(dissect_isakmp, proto_isakmp);
1353   dissector_add("udp.port", UDP_PORT_ISAKMP, isakmp_handle);
1354   dissector_add("tcp.port", TCP_PORT_ISAKMP, isakmp_handle);
1355 }