Obscure more email addresses.
[obnox/wireshark/wip.git] / packet-asap.c
1 /* packet-asap.c
2  * Routines for Aggregate Server Access Protocol
3  * It is hopefully (needs testing) compilant to
4  * http://www.ietf.org/internet-drafts/draft-ietf-rserpool-common-param-02.txt
5  * http://www.ietf.org/internet-drafts/draft-ietf-rserpool-asap-05.txt
6  *
7  * Copyright 2002, Michael Tuexen <Michael.Tuexen@siemens.com>
8  *
9  * $Id: packet-asap.c,v 1.8 2003/01/20 22:49:36 tuexen Exp $
10  *
11  * Ethereal - Network traffic analyzer
12  * By Gerald Combs <gerald@ethereal.com>
13  * Copyright 1998 Gerald Combs
14  *
15  * Copied from README.developer
16  *
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License
19  * as published by the Free Software Foundation; either version 2
20  * of the License, or (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <epan/packet.h>
37 #include "sctpppids.h"
38
39 /* Initialize the protocol and registered fields */
40 static int proto_asap = -1;
41 static int hf_cause_code = -1;
42 static int hf_cause_length = -1;
43 static int hf_cause_info = -1;
44 static int hf_cause_padding = -1;
45 static int hf_message_type = -1;
46 static int hf_message_flags = -1;
47 static int hf_message_length = -1;
48 static int hf_parameter_type = -1;
49 static int hf_parameter_length = -1;
50 static int hf_parameter_value = -1;
51 static int hf_parameter_padding = -1;
52 static int hf_parameter_ipv4_address = -1;
53 static int hf_parameter_ipv6_address = -1;
54 static int hf_sctp_port = -1;
55 static int hf_sctp_reserved = -1;
56 static int hf_tcp_port = -1;
57 static int hf_tcp_reserved = -1;
58 static int hf_udp_port = -1;
59 static int hf_udp_reserved = -1;
60 static int hf_policy_type = -1;
61 static int hf_policy_value = -1;
62 static int hf_pool_handle = -1;
63 static int hf_pe_pe_identifier = -1;
64 static int hf_home_enrp_id = -1;
65 static int hf_reg_life = -1;
66 static int hf_server_identifier = -1;
67 static int hf_m_bit = -1;
68 static int hf_reserved = -1;
69 static int hf_cookie = -1;
70 static int hf_pe_identifier = -1;
71
72 /* Initialize the subtree pointers */
73 static gint ett_asap = -1;
74 static gint ett_asap_parameter = -1;
75 static gint ett_asap_cause = -1;
76
77 static void
78 dissect_parameters(tvbuff_t *, proto_tree *);
79
80 #define NETWORK_BYTE_ORDER     FALSE
81 #define ADD_PADDING(x) ((((x) + 3) >> 2) << 2)
82
83 /* Dissectors for error causes */
84 #define CAUSE_CODE_LENGTH   2
85 #define CAUSE_LENGTH_LENGTH 2
86 #define CAUSE_HEADER_LENGTH (CAUSE_CODE_LENGTH + CAUSE_LENGTH_LENGTH)
87
88 #define CAUSE_HEADER_OFFSET 0
89 #define CAUSE_CODE_OFFSET   CAUSE_HEADER_OFFSET
90 #define CAUSE_LENGTH_OFFSET (CAUSE_CODE_OFFSET + CAUSE_CODE_LENGTH)
91 #define CAUSE_INFO_OFFSET   (CAUSE_LENGTH_OFFSET + CAUSE_LENGTH_LENGTH)
92
93 static void
94 dissect_unknown_cause(tvbuff_t *cause_tvb, proto_tree *cause_tree, proto_item *cause_item)
95 {
96   guint16 code, length, cause_info_length;
97
98   code              = tvb_get_ntohs(cause_tvb, CAUSE_CODE_OFFSET);
99   length            = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET);
100   cause_info_length = length - CAUSE_HEADER_LENGTH;
101   if (cause_info_length > 0)
102     proto_tree_add_bytes(cause_tree, hf_cause_info, cause_tvb, CAUSE_INFO_OFFSET, cause_info_length,
103                          tvb_get_ptr(cause_tvb, CAUSE_INFO_OFFSET, cause_info_length));
104   proto_item_append_text(cause_item, " (code %u and %u byte%s information)", code, cause_info_length, plurality(cause_info_length, "", "s"));
105 }
106
107 #define UNRECOGNIZED_PARAMETER_CAUSE_CODE      1
108 #define UNRECONGNIZED_MESSAGE_CAUSE_CODE       2
109 #define INVALID_VALUES                         3
110 #define NON_UNIQUE_PE_IDENTIFIER               4
111 #define POOLING_POLICY_INCONSISTENT_CAUSE_CODE 5
112 #define LACK_OF_RESOURCES_CAUSE_CODE           6
113
114 static const value_string cause_code_values[] = {
115   { UNRECOGNIZED_PARAMETER_CAUSE_CODE,      "Unrecognized parameter"      },
116   { UNRECONGNIZED_MESSAGE_CAUSE_CODE,       "Unrecognized message"        },
117   { INVALID_VALUES,                         "Invalid values"              },
118   { NON_UNIQUE_PE_IDENTIFIER,               "Non-unique PE identifier"    },
119   { POOLING_POLICY_INCONSISTENT_CAUSE_CODE, "Pooling policy inconsistent" },
120   { LACK_OF_RESOURCES_CAUSE_CODE,           "Lack of resources"           },
121   { 0,                                      NULL                          } };
122
123 static void
124 dissect_error_cause(tvbuff_t *cause_tvb, proto_tree *parameter_tree)
125 {
126   guint16 code, length, padding_length;
127   proto_item *cause_item;
128   proto_tree *cause_tree;
129
130   code           = tvb_get_ntohs(cause_tvb, CAUSE_CODE_OFFSET);
131   length         = tvb_get_ntohs(cause_tvb, CAUSE_LENGTH_OFFSET);
132   padding_length = tvb_length(cause_tvb) - length;
133
134   cause_item = proto_tree_add_text(parameter_tree, cause_tvb, CAUSE_HEADER_OFFSET, tvb_length(cause_tvb), val_to_str(code, cause_code_values, "Unknown error cause"));
135   cause_tree = proto_item_add_subtree(cause_item, ett_asap_cause);
136
137   proto_tree_add_item(cause_tree, hf_cause_code,   cause_tvb, CAUSE_CODE_OFFSET,   CAUSE_CODE_LENGTH,   NETWORK_BYTE_ORDER);
138   proto_tree_add_item(cause_tree, hf_cause_length, cause_tvb, CAUSE_LENGTH_OFFSET, CAUSE_LENGTH_LENGTH, NETWORK_BYTE_ORDER);
139
140   switch(code) {
141   default:
142     dissect_unknown_cause(cause_tvb, cause_tree, cause_item);
143     break;
144   }
145   if (padding_length > 0)
146     proto_tree_add_item(cause_tree, hf_cause_padding, cause_tvb, CAUSE_HEADER_OFFSET + length, padding_length, NETWORK_BYTE_ORDER);
147 }
148
149 static void
150 dissect_error_causes(tvbuff_t *error_causes_tvb, proto_tree *parameter_tree)
151 {
152   guint16 length, total_length;
153   gint offset;
154   tvbuff_t *error_cause_tvb;
155
156   offset = 0;
157   while(tvb_reported_length_remaining(error_causes_tvb, offset)) {
158     length          = tvb_get_ntohs(error_causes_tvb, offset + CAUSE_LENGTH_OFFSET);
159     total_length    = ADD_PADDING(length);
160     error_cause_tvb = tvb_new_subset(error_causes_tvb, offset , total_length, total_length);
161     dissect_error_cause(error_cause_tvb, parameter_tree);
162     offset += total_length;
163   }
164 }
165
166 /* Dissectors for parameters */
167
168 #define PARAMETER_TYPE_LENGTH   2
169 #define PARAMETER_LENGTH_LENGTH 2
170 #define PARAMETER_HEADER_LENGTH (PARAMETER_TYPE_LENGTH + PARAMETER_LENGTH_LENGTH)
171
172 #define PARAMETER_HEADER_OFFSET 0
173 #define PARAMETER_TYPE_OFFSET   PARAMETER_HEADER_OFFSET
174 #define PARAMETER_LENGTH_OFFSET (PARAMETER_TYPE_OFFSET + PARAMETER_TYPE_LENGTH)
175 #define PARAMETER_VALUE_OFFSET  (PARAMETER_LENGTH_OFFSET + PARAMETER_LENGTH_LENGTH)
176
177 #define IPV4_ADDRESS_LENGTH 4
178 #define IPV4_ADDRESS_OFFSET PARAMETER_VALUE_OFFSET
179
180 static void
181 dissect_ipv4_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
182 {
183   proto_tree_add_item(parameter_tree, hf_parameter_ipv4_address, parameter_tvb, IPV4_ADDRESS_OFFSET, IPV4_ADDRESS_LENGTH, NETWORK_BYTE_ORDER);
184   proto_item_append_text(parameter_item, " (%s)", ip_to_str((const guint8 *)tvb_get_ptr(parameter_tvb, IPV4_ADDRESS_OFFSET, IPV4_ADDRESS_LENGTH)));
185 }
186
187 #define IPV6_ADDRESS_LENGTH 16
188 #define IPV6_ADDRESS_OFFSET PARAMETER_VALUE_OFFSET
189
190 static void
191 dissect_ipv6_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
192 {
193   proto_tree_add_item(parameter_tree, hf_parameter_ipv6_address, parameter_tvb, IPV6_ADDRESS_OFFSET, IPV6_ADDRESS_LENGTH, NETWORK_BYTE_ORDER);
194   proto_item_append_text(parameter_item, " (%s)", ip6_to_str((const struct e_in6_addr *)tvb_get_ptr(parameter_tvb, IPV6_ADDRESS_OFFSET, IPV6_ADDRESS_LENGTH)));
195 }
196
197 #define SCTP_PORT_LENGTH     2
198 #define SCTP_RESERVED_LENGTH 2
199 #define SCTP_PORT_OFFSET     PARAMETER_VALUE_OFFSET
200 #define SCTP_RESERVED_OFFSET (SCTP_PORT_OFFSET + SCTP_PORT_LENGTH)
201 #define SCTP_ADDRESS_OFFSET  (SCTP_RESERVED_OFFSET + SCTP_RESERVED_LENGTH)
202
203 static void
204 dissect_sctp_transport_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
205 {
206   tvbuff_t *parameters_tvb;
207
208   proto_tree_add_item(parameter_tree, hf_sctp_port,     parameter_tvb, SCTP_PORT_OFFSET,     SCTP_PORT_LENGTH,     NETWORK_BYTE_ORDER);
209   proto_tree_add_item(parameter_tree, hf_sctp_reserved, parameter_tvb, SCTP_RESERVED_OFFSET, SCTP_RESERVED_LENGTH, NETWORK_BYTE_ORDER);
210
211   parameters_tvb = tvb_new_subset(parameter_tvb, SCTP_ADDRESS_OFFSET, -1, -1);
212   dissect_parameters(parameters_tvb, parameter_tree);
213 }
214
215 #define TCP_PORT_LENGTH     2
216 #define TCP_RESERVED_LENGTH 2
217 #define TCP_PORT_OFFSET     PARAMETER_VALUE_OFFSET
218 #define TCP_RESERVED_OFFSET (TCP_PORT_OFFSET + TCP_PORT_LENGTH)
219 #define TCP_ADDRESS_OFFSET  (TCP_RESERVED_OFFSET + TCP_RESERVED_LENGTH)
220
221 static void
222 dissect_tcp_transport_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
223 {
224   tvbuff_t *parameters_tvb;
225
226   proto_tree_add_item(parameter_tree, hf_tcp_port,     parameter_tvb, TCP_PORT_OFFSET,     TCP_PORT_LENGTH,     NETWORK_BYTE_ORDER);
227   proto_tree_add_item(parameter_tree, hf_tcp_reserved, parameter_tvb, TCP_RESERVED_OFFSET, TCP_RESERVED_LENGTH, NETWORK_BYTE_ORDER);
228
229   parameters_tvb = tvb_new_subset(parameter_tvb, TCP_ADDRESS_OFFSET, -1, -1);
230   dissect_parameters(parameters_tvb, parameter_tree);
231 }
232
233 #define UDP_PORT_LENGTH     2
234 #define UDP_RESERVED_LENGTH 2
235 #define UDP_PORT_OFFSET     PARAMETER_VALUE_OFFSET
236 #define UDP_RESERVED_OFFSET (UDP_PORT_OFFSET + UDP_PORT_LENGTH)
237 #define UDP_ADDRESS_OFFSET  (UDP_RESERVED_OFFSET + UDP_RESERVED_LENGTH)
238
239 static void
240 dissect_udp_transport_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
241 {
242   tvbuff_t *parameters_tvb;
243
244   proto_tree_add_item(parameter_tree, hf_udp_port,     parameter_tvb, UDP_PORT_OFFSET,     UDP_PORT_LENGTH,     NETWORK_BYTE_ORDER);
245   proto_tree_add_item(parameter_tree, hf_udp_reserved, parameter_tvb, UDP_RESERVED_OFFSET, UDP_RESERVED_LENGTH, NETWORK_BYTE_ORDER);
246
247   parameters_tvb = tvb_new_subset(parameter_tvb, UDP_ADDRESS_OFFSET, -1, -1);
248   dissect_parameters(parameters_tvb, parameter_tree);
249 }
250
251 #define POLICY_TYPE_LENGTH   1
252 #define POLICY_VALUE_LENGTH  3
253
254 #define POLICY_TYPE_OFFSET   PARAMETER_VALUE_OFFSET
255 #define POLICY_VALUE_OFFSET  (POLICY_TYPE_OFFSET + POLICY_TYPE_LENGTH)
256
257 #define ROUND_ROBIN_POLICY   1
258 #define LEAST_USED_POLICY    2
259 #define LEAST_USED_WITH_DEG  3
260 #define WEIGHTED_ROUND_ROBIN 4
261
262 static const value_string policy_type_values[] = {
263   { ROUND_ROBIN_POLICY,   "Round robin" },
264   { LEAST_USED_POLICY,    "Least used" },
265   { LEAST_USED_WITH_DEG,  "Least used with degradation" },
266   { WEIGHTED_ROUND_ROBIN, "Weighted round robin" },
267   { 0,                    NULL } };
268
269 static void
270 dissect_pool_member_selection_policy_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
271 {
272   proto_tree_add_item(parameter_tree, hf_policy_type,  parameter_tvb, POLICY_TYPE_OFFSET,  POLICY_TYPE_LENGTH,  NETWORK_BYTE_ORDER);
273   proto_tree_add_item(parameter_tree, hf_policy_value, parameter_tvb, POLICY_VALUE_OFFSET, POLICY_VALUE_LENGTH, NETWORK_BYTE_ORDER);
274 }
275
276 #define POOL_HANDLE_OFFSET PARAMETER_VALUE_OFFSET
277
278 static void
279 dissect_pool_handle_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
280 {
281   guint16 handle_length;
282
283   handle_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
284   proto_tree_add_item(parameter_tree, hf_pool_handle, parameter_tvb, POOL_HANDLE_OFFSET, handle_length, NETWORK_BYTE_ORDER);
285 }
286
287 #define PE_PE_IDENTIFIER_LENGTH         4
288 #define HOME_ENRP_INDENTIFIER_LENGTH    4
289 #define REGISTRATION_LIFE_LENGTH        4
290
291 #define PE_PE_IDENTIFIER_OFFSET         PARAMETER_VALUE_OFFSET
292 #define HOME_ENRP_INDENTIFIER_OFFSET    (PE_PE_IDENTIFIER_OFFSET + PE_PE_IDENTIFIER_LENGTH)
293 #define REGISTRATION_LIFE_OFFSET        (HOME_ENRP_INDENTIFIER_OFFSET + HOME_ENRP_INDENTIFIER_LENGTH)
294 #define USER_TRANSPORT_PARAMETER_OFFSET (REGISTRATION_LIFE_OFFSET + REGISTRATION_LIFE_LENGTH)
295
296 static void
297 dissect_pool_element_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
298 {
299   tvbuff_t *parameters_tvb;
300
301   proto_tree_add_item(parameter_tree, hf_pe_pe_identifier, parameter_tvb, PE_PE_IDENTIFIER_OFFSET,      PE_PE_IDENTIFIER_LENGTH,      NETWORK_BYTE_ORDER);
302   proto_tree_add_item(parameter_tree, hf_home_enrp_id,     parameter_tvb, HOME_ENRP_INDENTIFIER_OFFSET, HOME_ENRP_INDENTIFIER_LENGTH, NETWORK_BYTE_ORDER);
303   proto_tree_add_item(parameter_tree, hf_reg_life,         parameter_tvb, REGISTRATION_LIFE_OFFSET,     REGISTRATION_LIFE_LENGTH,     NETWORK_BYTE_ORDER);
304
305   parameters_tvb = tvb_new_subset(parameter_tvb, USER_TRANSPORT_PARAMETER_OFFSET, -1, -1);
306   dissect_parameters(parameters_tvb, parameter_tree);
307 }
308
309 #define SERVER_ID_LENGTH         4
310 #define RESERVED_LENGTH          4
311
312 #define SERVER_ID_OFFSET         PARAMETER_VALUE_OFFSET
313 #define RESERVED_OFFSET          (SERVER_ID_OFFSET + SERVER_ID_LENGTH)
314 #define SERVER_TRANSPORT_OFFSET  (RESERVED_OFFSET + RESERVED_LENGTH)
315
316 #define M_BIT_MASK               0x80000000
317 #define RESERVED_MASK            0x7fffffff
318
319 static void
320 dissect_server_information_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
321 {
322   tvbuff_t *parameters_tvb;
323
324   proto_tree_add_item(parameter_tree, hf_server_identifier, parameter_tvb, SERVER_ID_OFFSET, SERVER_ID_LENGTH, NETWORK_BYTE_ORDER);
325   proto_tree_add_item(parameter_tree, hf_m_bit,             parameter_tvb, RESERVED_OFFSET,  RESERVED_LENGTH,  NETWORK_BYTE_ORDER);
326   proto_tree_add_item(parameter_tree, hf_reserved,          parameter_tvb, RESERVED_OFFSET,  RESERVED_LENGTH,  NETWORK_BYTE_ORDER);
327
328   parameters_tvb = tvb_new_subset(parameter_tvb, SERVER_TRANSPORT_OFFSET, -1, -1);
329   dissect_parameters(parameters_tvb, parameter_tree);
330 }
331
332 #define ERROR_CAUSES_OFFSET PARAMETER_VALUE_OFFSET
333
334 static void
335 dissect_operation_error_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree)
336 {
337   tvbuff_t *error_causes_tvb;
338
339   error_causes_tvb = tvb_new_subset(parameter_tvb, ERROR_CAUSES_OFFSET, -1,-1);
340   dissect_error_causes(error_causes_tvb, parameter_tree);
341 }
342
343 #define COOKIE_OFFSET PARAMETER_VALUE_OFFSET
344
345 static void
346 dissect_cookie_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
347 {
348   guint16 cookie_length;
349
350   cookie_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
351   if (cookie_length > 0)
352     proto_tree_add_item(parameter_tree, hf_cookie, parameter_tvb, COOKIE_OFFSET, cookie_length, NETWORK_BYTE_ORDER);
353   proto_item_append_text(parameter_item, " (%u byte%s)", cookie_length, plurality(cookie_length, "", "s"));
354 }
355
356 #define PE_IDENTIFIER_LENGTH 4
357 #define PE_IDENTIFIER_OFFSET PARAMETER_VALUE_OFFSET
358
359 static void
360 dissect_pe_identifier_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
361 {
362   proto_tree_add_item(parameter_tree, hf_pe_identifier, parameter_tvb, PE_IDENTIFIER_OFFSET, PE_IDENTIFIER_LENGTH, NETWORK_BYTE_ORDER);
363   proto_item_append_text(parameter_item, " (0x%x)", tvb_get_ntohl(parameter_tvb, PE_IDENTIFIER_OFFSET));
364 }
365
366 static void
367 dissect_unknown_parameter(tvbuff_t *parameter_tvb, proto_tree *parameter_tree, proto_item *parameter_item)
368 {
369   guint16 type, parameter_value_length;
370
371   type                   = tvb_get_ntohs(parameter_tvb, PARAMETER_TYPE_OFFSET);
372   parameter_value_length = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET) - PARAMETER_HEADER_LENGTH;
373
374   if (parameter_value_length > 0)
375     proto_tree_add_item(parameter_tree, hf_parameter_value, parameter_tvb, PARAMETER_VALUE_OFFSET, parameter_value_length, NETWORK_BYTE_ORDER);
376
377   proto_item_append_text(parameter_item, " (type %u and %u byte%s value)", type, parameter_value_length, plurality(parameter_value_length, "", "s"));
378 }
379
380 #define IPV4_ADDRESS_PARAMETER_TYPE                 0x01
381 #define IPV6_ADDRESS_PARAMETER_TYPE                 0x02
382 #define SCTP_TRANSPORT_PARAMETER_TYPE               0x03
383 #define TCP_TRANSPORT_PARAMETER_TYPE                0x04
384 #define UDP_TRANSPORT_PARAMETER_TYPE                0x05
385 #define POOL_MEMBER_SELECTION_POLICY_PARAMETER_TYPE 0x06
386 #define POOL_HANDLE_PARAMETER_TYPE                  0x07
387 #define POOL_ELEMENT_PARAMETER_TYPE                 0x08
388 #define SERVER_INFORMATION_PARAMETER_TYPE           0x09
389 #define OPERATION_ERROR_PARAMETER_TYPE              0x0a
390 #define COOKIE_PARAMETER_TYPE                       0x0b
391 #define PE_IDENTIFIER_PARAMETER_TYPE                0x0c
392
393 static const value_string parameter_type_values[] = {
394   { IPV4_ADDRESS_PARAMETER_TYPE,                 "IPV4 address" },
395   { IPV6_ADDRESS_PARAMETER_TYPE,                 "IPV6 address" },
396   { SCTP_TRANSPORT_PARAMETER_TYPE,               "SCTP transport address" },
397   { TCP_TRANSPORT_PARAMETER_TYPE,                "TCP transport address" },
398   { UDP_TRANSPORT_PARAMETER_TYPE,                "UDP transport address" },
399   { POOL_MEMBER_SELECTION_POLICY_PARAMETER_TYPE, "Pool member selection policy" },
400   { POOL_HANDLE_PARAMETER_TYPE,                  "Pool handle" },
401   { POOL_ELEMENT_PARAMETER_TYPE,                 "Pool element" },
402   { SERVER_INFORMATION_PARAMETER_TYPE,           "Server Information" },
403   { OPERATION_ERROR_PARAMETER_TYPE,              "Operation error" },
404   { COOKIE_PARAMETER_TYPE,                       "Cookie" },
405   { PE_IDENTIFIER_PARAMETER_TYPE,                "Pool Element identifier" },
406   { 0,                                           NULL } };
407
408
409 static void
410 dissect_parameter(tvbuff_t *parameter_tvb, proto_tree *asap_tree)
411 {
412   guint16 type, length, padding_length;
413   proto_item *parameter_item;
414   proto_tree *parameter_tree;
415
416   /* extract tag and length from the parameter */
417   type           = tvb_get_ntohs(parameter_tvb, PARAMETER_TYPE_OFFSET);
418   length         = tvb_get_ntohs(parameter_tvb, PARAMETER_LENGTH_OFFSET);
419   padding_length = tvb_length(parameter_tvb) - length;
420
421   /* create proto_tree stuff */
422   parameter_item   = proto_tree_add_text(asap_tree, parameter_tvb, PARAMETER_HEADER_OFFSET, tvb_length(parameter_tvb), val_to_str(type, parameter_type_values, "Unknown parameter"));
423   parameter_tree   = proto_item_add_subtree(parameter_item, ett_asap_parameter);
424
425   /* add tag and length to the asap tree */
426   proto_tree_add_item(parameter_tree, hf_parameter_type,   parameter_tvb, PARAMETER_TYPE_OFFSET,   PARAMETER_TYPE_LENGTH,   NETWORK_BYTE_ORDER);
427   proto_tree_add_item(parameter_tree, hf_parameter_length, parameter_tvb, PARAMETER_LENGTH_OFFSET, PARAMETER_LENGTH_LENGTH, NETWORK_BYTE_ORDER);
428
429   switch(type) {
430   case IPV4_ADDRESS_PARAMETER_TYPE:
431     dissect_ipv4_parameter(parameter_tvb, parameter_tree, parameter_item);
432     break;
433   case IPV6_ADDRESS_PARAMETER_TYPE:
434     dissect_ipv6_parameter(parameter_tvb, parameter_tree, parameter_item);
435     break;
436   case SCTP_TRANSPORT_PARAMETER_TYPE:
437     dissect_sctp_transport_parameter(parameter_tvb, parameter_tree);
438     break;
439   case TCP_TRANSPORT_PARAMETER_TYPE:
440     dissect_tcp_transport_parameter(parameter_tvb, parameter_tree);
441     break;
442   case UDP_TRANSPORT_PARAMETER_TYPE:
443     dissect_udp_transport_parameter(parameter_tvb, parameter_tree);
444     break;
445   case POOL_MEMBER_SELECTION_POLICY_PARAMETER_TYPE:
446     dissect_pool_member_selection_policy_parameter(parameter_tvb, parameter_tree);
447     break;
448   case POOL_HANDLE_PARAMETER_TYPE:
449     dissect_pool_handle_parameter(parameter_tvb, parameter_tree);
450     break;
451   case POOL_ELEMENT_PARAMETER_TYPE:
452     dissect_pool_element_parameter(parameter_tvb, parameter_tree);
453     break;
454   case SERVER_INFORMATION_PARAMETER_TYPE:
455     dissect_server_information_parameter(parameter_tvb, parameter_tree);
456     break;
457   case OPERATION_ERROR_PARAMETER_TYPE:
458     dissect_operation_error_parameter(parameter_tvb, parameter_tree);
459     break;
460   case COOKIE_PARAMETER_TYPE:
461     dissect_cookie_parameter(parameter_tvb, parameter_tree, parameter_item);
462     break;
463   case PE_IDENTIFIER_PARAMETER_TYPE:
464     dissect_pe_identifier_parameter(parameter_tvb, parameter_tree, parameter_item);
465     break;
466   default:
467     dissect_unknown_parameter(parameter_tvb, parameter_tree, parameter_item);
468     break;
469   };
470
471   if (padding_length > 0)
472     proto_tree_add_item(parameter_tree, hf_parameter_padding, parameter_tvb, PARAMETER_HEADER_OFFSET + length, padding_length, NETWORK_BYTE_ORDER);
473 }
474
475 static void
476 dissect_parameters(tvbuff_t *parameters_tvb, proto_tree *tree)
477 {
478   gint offset, length, total_length, remaining_length;
479   tvbuff_t *parameter_tvb;
480
481   offset = 0;
482   while((remaining_length = tvb_length_remaining(parameters_tvb, offset))) {
483     length       = tvb_get_ntohs(parameters_tvb, offset + PARAMETER_LENGTH_OFFSET);
484     total_length = ADD_PADDING(length);
485     if (remaining_length >= length)
486       total_length = MIN(total_length, remaining_length);
487     /* create a tvb for the parameter including the padding bytes */
488     parameter_tvb  = tvb_new_subset(parameters_tvb, offset, total_length, total_length);
489     dissect_parameter(parameter_tvb, tree);
490     /* get rid of the handled parameter */
491     offset += total_length;
492   }
493 }
494
495 #define MESSAGE_TYPE_LENGTH   1
496 #define MESSAGE_FLAGS_LENGTH  1
497 #define MESSAGE_LENGTH_LENGTH 2
498
499 #define MESSAGE_TYPE_OFFSET   0
500 #define MESSAGE_FLAGS_OFFSET  (MESSAGE_TYPE_OFFSET   + MESSAGE_TYPE_LENGTH)
501 #define MESSAGE_LENGTH_OFFSET (MESSAGE_FLAGS_OFFSET  + MESSAGE_FLAGS_LENGTH)
502 #define MESSAGE_VALUE_OFFSET  (MESSAGE_LENGTH_OFFSET + MESSAGE_LENGTH_LENGTH)
503
504 #define REGISTRATION_MESSAGE_TYPE             0x01
505 #define DEREGISTRATION_MESSAGE_TYPE           0x02
506 #define REGISTRATION_RESPONSE_MESSAGE_TYPE    0x03
507 #define DEREGISTRATION_RESPONSE_MESSAGE_TYPE  0x04
508 #define NAME_RESOLUTION_MESSAGE_TYPE          0x05
509 #define NAME_RESOLUTION_RESPONSE_MESSAGE_TYPE 0x06
510 #define ENDPOINT_KEEP_ALIVE_MESSAGE_TYPE      0x07
511 #define ENDPOINT_KEEP_ALIVE_ACK_MESSAGE_TYPE  0x08
512 #define ENDPOINT_UNREACHABLE_MESSAGE_TYPE     0x09
513 #define SERVER_ANNOUNCE_MESSAGE_TYPE          0x0a
514 #define COOKIE_MESSAGE_TYPE                   0x0b
515 #define COOKIE_ECHO_MESSAGE_TYPE              0x0c
516 #define BUSINESS_CARD_MESSAGE_TYPE            0x0d
517 #define PEER_ERROR_MESSAGE_TYPE               0x0e
518
519 static const value_string message_type_values[] = {
520   { REGISTRATION_MESSAGE_TYPE,             "Registration" },
521   { DEREGISTRATION_MESSAGE_TYPE,           "Deregistration" },
522   { REGISTRATION_RESPONSE_MESSAGE_TYPE,    "Registration response" },
523   { DEREGISTRATION_RESPONSE_MESSAGE_TYPE,  "Deregistration response" },
524   { NAME_RESOLUTION_MESSAGE_TYPE,          "Name resolution" },
525   { NAME_RESOLUTION_RESPONSE_MESSAGE_TYPE, "Name resolution response" },
526   { ENDPOINT_KEEP_ALIVE_MESSAGE_TYPE,      "Endpoint keep alive" },
527   { ENDPOINT_KEEP_ALIVE_ACK_MESSAGE_TYPE,  "Endpoint keep alive acknowledgement" },
528   { ENDPOINT_UNREACHABLE_MESSAGE_TYPE,     "Endpoint unreachable" },
529   { SERVER_ANNOUNCE_MESSAGE_TYPE,          "Server announce" },
530   { COOKIE_MESSAGE_TYPE,                   "Cookie" },
531   { COOKIE_ECHO_MESSAGE_TYPE,              "Cookie echo" },
532   { BUSINESS_CARD_MESSAGE_TYPE,            "Business card" },
533   { PEER_ERROR_MESSAGE_TYPE,               "Peer error" },
534   { 0,                                     NULL } };
535
536 static void
537 dissect_asap_message(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *asap_tree)
538 {
539   tvbuff_t *parameters_tvb;
540
541   if (check_col(pinfo->cinfo, COL_INFO)) {
542     col_append_str(pinfo->cinfo, COL_INFO, val_to_str(tvb_get_guint8(message_tvb, MESSAGE_TYPE_OFFSET), message_type_values, "Unknown ASAP type"));
543     col_append_str(pinfo->cinfo, COL_INFO, " ");
544   }
545   if (asap_tree) {
546     proto_tree_add_item(asap_tree, hf_message_type,   message_tvb, MESSAGE_TYPE_OFFSET,   MESSAGE_TYPE_LENGTH,   NETWORK_BYTE_ORDER);
547     proto_tree_add_item(asap_tree, hf_message_flags,  message_tvb, MESSAGE_FLAGS_OFFSET,  MESSAGE_FLAGS_LENGTH,  NETWORK_BYTE_ORDER);
548     proto_tree_add_item(asap_tree, hf_message_length, message_tvb, MESSAGE_LENGTH_OFFSET, MESSAGE_LENGTH_LENGTH, NETWORK_BYTE_ORDER);
549     parameters_tvb    = tvb_new_subset(message_tvb, MESSAGE_VALUE_OFFSET, -1, -1);
550     dissect_parameters(parameters_tvb, asap_tree);
551     }
552 }
553
554 static void
555 dissect_asap(tvbuff_t *message_tvb, packet_info *pinfo, proto_tree *tree)
556 {
557   proto_item *asap_item;
558   proto_tree *asap_tree;
559
560   /* make entry in the Protocol column on summary display */
561   if (check_col(pinfo->cinfo, COL_PROTOCOL))
562     col_set_str(pinfo->cinfo, COL_PROTOCOL, "ASAP");
563
564   /* In the interest of speed, if "tree" is NULL, don't do any work not
565      necessary to generate protocol tree items. */
566   if (tree) {
567     /* create the asap protocol tree */
568     asap_item = proto_tree_add_item(tree, proto_asap, message_tvb, 0, -1, FALSE);
569     asap_tree = proto_item_add_subtree(asap_item, ett_asap);
570   } else {
571     asap_tree = NULL;
572   };
573   /* dissect the message */
574   dissect_asap_message(message_tvb, pinfo, asap_tree);
575 }
576
577 /* Register the protocol with Ethereal */
578 void
579 proto_register_asap(void)
580 {
581
582   /* Setup list of header fields */
583   static hf_register_info hf[] = {
584     { &hf_message_type,           { "Type",                        "asap.message_type",                             FT_UINT8,   BASE_DEC,  VALS(message_type_values),   0x0,           "", HFILL } },
585     { &hf_message_flags,          { "Flags",                       "asap.message_flags",                            FT_UINT8,   BASE_HEX,  NULL,                        0x0,           "", HFILL } },
586     { &hf_message_length,         { "Length",                      "asap.message_length",                           FT_UINT16,  BASE_DEC,  NULL,                        0x0,           "", HFILL } },
587     { &hf_cause_code,             { "Cause code",                  "asap.cause.code",                               FT_UINT16,  BASE_HEX,  VALS(cause_code_values),     0x0,           "", HFILL } },
588     { &hf_cause_length,           { "Cause length",                "asap.cause.length",                             FT_UINT16,  BASE_DEC,  NULL,                        0x0,           "", HFILL } },
589     { &hf_cause_info,             { "Cause info",                  "asap.cause.info",                               FT_BYTES,   BASE_NONE, NULL,                        0x0,           "", HFILL } },
590     { &hf_cause_padding,          { "Padding",                     "asap.cause.padding",                            FT_BYTES,   BASE_NONE, NULL,                        0x0,           "", HFILL } },
591     { &hf_parameter_type,         { "Parameter Type",              "asap.parameter.type",                           FT_UINT16,  BASE_HEX,  VALS(parameter_type_values), 0x0,           "", HFILL } },
592     { &hf_parameter_length,       { "Parameter length",            "asap.parameter.length",                         FT_UINT16,  BASE_DEC,  NULL,                        0x0,           "", HFILL } },
593     { &hf_parameter_value,        { "Parameter value",             "asap.parameter.value",                          FT_BYTES,   BASE_NONE, NULL,                        0x0,           "", HFILL } },
594     { &hf_parameter_padding,      { "Padding",                     "asap.parameter.padding",                        FT_BYTES,   BASE_NONE, NULL,                        0x0,           "", HFILL } },
595     { &hf_parameter_ipv4_address, { "IP Version 4 address",        "asap.ipv4_address.ipv4_address",                FT_IPv4,    BASE_NONE, NULL,                        0x0,           "", HFILL } },
596     { &hf_parameter_ipv6_address, { "IP Version 6 address",        "asap.ipv6_address.ipv6_address",                FT_IPv6,    BASE_NONE, NULL,                        0x0,           "", HFILL } },
597     { &hf_sctp_port,              { "Port",                        "asap.sctp_transport.port",                      FT_UINT16,  BASE_DEC,  NULL,                        0x0,           "", HFILL } },
598     { &hf_sctp_reserved,          { "Reserved",                    "asap.sctp_transport.reserved",                  FT_UINT16,  BASE_DEC,  NULL,                        0x0,           "", HFILL } },
599     { &hf_tcp_port,               { "Port",                        "asap.tcp_transport.port",                       FT_UINT16,  BASE_DEC,  NULL,                        0x0,           "", HFILL } },
600     { &hf_tcp_reserved,           { "Reserved",                    "asap.tcp_transport.reserved",                   FT_UINT16,  BASE_DEC,  NULL,                        0x0,           "", HFILL } },
601     { &hf_udp_port,               { "Port",                        "asap.udp_transport.port",                       FT_UINT16,  BASE_DEC,  NULL,                        0x0,           "", HFILL } },
602     { &hf_udp_reserved,           { "Reserved",                    "asap.udp_transport.reserved",                   FT_UINT16,  BASE_DEC,  NULL,                        0x0,           "", HFILL } },
603     { &hf_policy_type,            { "Policy type",                 "asap.pool_member_slection_policy.type",         FT_UINT8,   BASE_DEC,  VALS(policy_type_values),    0x0,           "", HFILL } },
604     { &hf_policy_value,           { "Policy value",                "asap.pool_member_slection_policy.value",        FT_INT24,   BASE_DEC,  NULL,                        0x0,           "", HFILL } },
605     { &hf_pool_handle,            { "Pool handle",                 "asap.pool_handle.pool_handle",                  FT_BYTES,   BASE_HEX,  NULL,                        0x0,           "", HFILL } },
606     { &hf_pe_pe_identifier,       { "PE identifier",               "asap.pool_element.pe_identifier",               FT_UINT32,  BASE_HEX,  NULL,                        0x0,           "", HFILL } },
607     { &hf_home_enrp_id,           { "Home ENRP server identifier", "asap.pool_element.home_enrp_server_identifier", FT_UINT32,  BASE_HEX,  NULL,                        0x0,           "", HFILL } },
608     { &hf_reg_life,               { "Registration life",           "asap.pool_element.registration_life",           FT_INT32,   BASE_DEC,  NULL,                        0x0,           "", HFILL } },
609     { &hf_server_identifier,      { "Server identifier",           "asap.server_information.server_identifier",     FT_UINT32,  BASE_HEX,  NULL,                        0x0,           "", HFILL } },
610     { &hf_m_bit,                  { "M-Bit",                       "asap.server_information.m_bit",                 FT_BOOLEAN, 32,        NULL,                        M_BIT_MASK,    "", HFILL } },
611     { &hf_reserved,               { "Reserved",                    "asap.server_information.reserved",              FT_UINT32,  BASE_HEX,  NULL,                        RESERVED_MASK, "", HFILL } },
612     { &hf_cookie,                 { "Cookie",                      "asap.cookie.cookie",                            FT_BYTES,   BASE_HEX,  NULL,                        0x0,           "", HFILL } },
613     { &hf_pe_identifier,          { "PE identifier",               "asap.pe_identifier.pe_identifier",              FT_UINT32,  BASE_HEX,  NULL,                        0x0,           "", HFILL } },
614   };
615
616   /* Setup protocol subtree array */
617   static gint *ett[] = {
618     &ett_asap,
619     &ett_asap_parameter,
620     &ett_asap_cause,
621   };
622
623   /* Register the protocol name and description */
624   proto_asap = proto_register_protocol("Aggregate Server Access Protocol", "ASAP",  "asap");
625
626   /* Required function calls to register the header fields and subtrees used */
627   proto_register_field_array(proto_asap, hf, array_length(hf));
628   proto_register_subtree_array(ett, array_length(ett));
629
630 };
631
632 void
633 proto_reg_handoff_asap(void)
634 {
635   dissector_handle_t asap_handle;
636
637   asap_handle = create_dissector_handle(dissect_asap, proto_asap);
638   dissector_add("sctp.ppi",  ASAP_PAYLOAD_PROTOCOL_ID, asap_handle);
639 }