Fixup: tvb_get_string(z) -> tvb_get_string(z)_enc
[metze/wireshark/wip.git] / epan / dissectors / packet-agentx.c
1 /* packet-agentx.c
2  * Routines for Agent Extensibility (AgentX) Protocol disassembly
3  * RFC 2257
4  *
5  * Copyright (c) 2005 by Oleg Terletsky <oleg.terletsky@comverse.com>
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1999 Gerald Combs
10  *
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include "config.h"
27
28 #include <epan/packet.h>
29 #include <epan/prefs.h>
30 #include <epan/to_str.h>
31
32 #include <epan/dissectors/packet-tcp.h>
33
34 static guint global_agentx_tcp_port = 705;
35
36 void proto_register_agentx(void);
37 void proto_reg_handoff_agentx(void);
38
39
40 /* Define the agentx proto */
41 static int proto_agentx = -1;
42
43
44 static int hf_version = -1;
45 static int hf_type   = -1;
46 /* static int hf_flags  = -1; */
47 static int hf_flags_register  = -1;
48 static int hf_flags_newindex  = -1;
49 static int hf_flags_anyindex  = -1;
50 static int hf_flags_context  = -1;
51 static int hf_flags_byteorder  = -1;
52 static int hf_session_id = -1;
53 static int hf_trans_id = -1;
54 static int hf_packet_id = -1;
55 static int hf_payload_len = -1;
56 static int hf_ostring_len = -1;
57 static int hf_ostring  = -1;
58 static int hf_oid_sub = -1;
59 static int hf_oid_prefix = -1;
60 static int hf_oid_include = -1;
61 static int hf_oid_str = -1;
62 static int hf_resp_uptime = -1;
63 static int hf_resp_error = -1;
64 static int hf_resp_index = -1;
65 static int hf_vtag = -1;
66 static int hf_val32 = -1;
67 static int hf_val64 = -1;
68 static int hf_open_timeout = -1;
69 static int hf_close_reason = -1;
70 static int hf_reg_timeout = -1;
71 static int hf_reg_prio = -1;
72 static int hf_reg_rsid = -1;
73 static int hf_reg_ubound = -1;
74 static int hf_unreg_timeout = -1;
75 static int hf_unreg_prio = -1;
76 static int hf_unreg_rsid = -1;
77 static int hf_unreg_ubound = -1;
78 static int hf_gbulk_nrepeat = -1;
79 static int hf_gbulk_mrepeat = -1;
80
81
82 static gint ett_flags = -1;
83 static gint ett_agentx = -1;
84 static gint ett_pdu_hdr = -1;
85 static gint ett_get = -1;
86 static gint ett_getnext = -1;
87 static gint ett_search_range = -1;
88 static gint ett_obj_ident = -1;
89 static gint ett_response = -1;
90 static gint ett_valrep = -1;
91 static gint ett_open = -1;
92 static gint ett_close = -1;
93 static gint ett_register = -1;
94 static gint ett_unregister = -1;
95 static gint ett_getbulk = -1;
96 static gint ett_testset = -1;
97 static gint ett_commitset = -1;
98 static gint ett_undoset = -1;
99 static gint ett_cleanupset = -1;
100 static gint ett_notify = -1;
101 static gint ett_ping = -1;
102 static gint ett_idxalloc = -1;
103 static gint ett_idxdalloc = -1;
104 static gint ett_addcap = -1;
105 static gint ett_remcap = -1;
106
107
108 #define         AGENTX_OPEN_PDU                  1
109 #define         AGENTX_CLOSE_PDU                 2
110 #define         AGENTX_REGISTER_PDU              3
111 #define         AGENTX_UNREGISTER_PDU            4
112 #define         AGENTX_GET_PDU                   5
113 #define         AGENTX_GETNEXT_PDU               6
114 #define         AGENTX_GETBULK_PDU               7
115 #define         AGENTX_TESTSET_PDU               8
116 #define         AGENTX_COMMITSET_PDU             9
117 #define         AGENTX_UNDOSET_PDU              10
118 #define         AGENTX_CLEANUPSET_PDU           11
119 #define         AGENTX_NOTIFY_PDU               12
120 #define         AGENTX_PING_PDU                 13
121 #define         AGENTX_INDEX_ALLOC_PDU          14
122 #define         AGENTX_INDEX_DEALLOC_PDU        15
123 #define         AGENTX_ADD_AGENT_CAPS_PDU       16
124 #define         AGENTX_REM_AGENT_CAPS_PDU       17
125 #define         AGENTX_RESPONSE_PDU             18
126
127
128 static const value_string type_values [] = {
129         { AGENTX_OPEN_PDU,              "Open-PDU" },
130         { AGENTX_CLOSE_PDU,             "Close-PDU" },
131         { AGENTX_REGISTER_PDU,          "Register-PDU" },
132         { AGENTX_UNREGISTER_PDU,        "Unregister-PDU" },
133         { AGENTX_GET_PDU,               "Get-PDU" },
134         { AGENTX_GETNEXT_PDU,           "GetNext-PDU" },
135         { AGENTX_GETBULK_PDU,           "GetBulk-PDU" },
136         { AGENTX_TESTSET_PDU,           "TestSet-PDU" },
137         { AGENTX_COMMITSET_PDU,         "CommitSet-PDU" },
138         { AGENTX_UNDOSET_PDU,           "UndoSet-PDU" },
139         { AGENTX_CLEANUPSET_PDU,        "CleanupSet-PDU" },
140         { AGENTX_NOTIFY_PDU,            "Notify-PDU" },
141         { AGENTX_PING_PDU,              "Ping-PDU" },
142         { AGENTX_INDEX_ALLOC_PDU,       "IndexAllocate-PDU" },
143         { AGENTX_INDEX_DEALLOC_PDU,     "IndexDeallocate-PDU" },
144         { AGENTX_ADD_AGENT_CAPS_PDU,    "AddAgentCaps-PDU" },
145         { AGENTX_REM_AGENT_CAPS_PDU,    "RemoveAgentCaps-PDU" },
146         { AGENTX_RESPONSE_PDU,          "Response-PDU" },
147         { 0, NULL }
148 };
149 static value_string_ext type_values_ext = VALUE_STRING_EXT_INIT(type_values);
150
151 /* VarBind types */
152
153 #define VB_INT            2
154 #define VB_OSTR           4
155 #define VB_NULL           5
156 #define VB_OID            6
157 #define VB_IPADDR        64
158 #define VB_COUNTER32     65
159 #define VB_GAUGE32       66
160 #define VB_TIMETICK      67
161 #define VB_OPAQUE        68
162 #define VB_COUNTER64     70
163 #define VB_NOSUCHOBJ    128
164 #define VB_NOSUCHINST   129
165 #define VB_ENDOFMIB     130
166
167
168 static const value_string vtag_values [] = {
169         { VB_INT,               "Integer" },
170         { VB_OSTR,              "Octet String" },
171         { VB_NULL,              "Null" },
172         { VB_OID,               "Object Identifier" },
173         { VB_IPADDR,            "IpAddress" },
174         { VB_COUNTER32,         "Counter32" },
175         { VB_GAUGE32,           "Gauge32" },
176         { VB_TIMETICK,          "TimeTicks" },
177         { VB_OPAQUE,            "Opaque" },
178         { VB_COUNTER64,         "Counter64" },
179         { VB_NOSUCHOBJ,         "noSuchObject" },
180         { VB_NOSUCHINST,        "noSuchInstance" },
181         { VB_ENDOFMIB,          "endOfMibView" },
182         { 0, NULL }
183 };
184 static value_string_ext vtag_values_ext = VALUE_STRING_EXT_INIT(vtag_values);
185
186 /* Close reasons */
187 #define CREASON_OTHER           1
188 #define CREASON_PARSE_ERROR     2
189 #define CREASON_PROTOCOL_ERROR  3
190 #define CREASON_TIMEOUTS        4
191 #define CREASON_SHUTDOWN        5
192 #define CREASON_BY_MANAGER      6
193
194
195 static const value_string close_reasons[] = {
196         { CREASON_OTHER,                "reasonOther" },
197         { CREASON_PARSE_ERROR,          "reasonParseError" },
198         { CREASON_PROTOCOL_ERROR,       "reasonProtocolError" },
199         { CREASON_TIMEOUTS,             "reasonTimeouts" },
200         { CREASON_SHUTDOWN ,            "reasonShutdown" },
201         { CREASON_BY_MANAGER,           "reasonByManager" },
202         { 0, NULL }
203 };
204
205
206 /* Response errors */
207 #define AGENTX_NO_ERROR           0
208 #define AGENTX_TOO_BIG            1
209 #define AGENTX_NO_SUCH_NAME       2
210 #define AGENTX_BAD_VALUE          3
211 #define AGENTX_READ_ONLY          4
212 #define AGENTX_GEN_ERROR          5
213 #define AGENTX_NO_ACCESS          6
214 #define AGENTX_WRONG_TYPE         7
215 #define AGENTX_WRONG_LEN          8
216 #define AGENTX_WRONG_ENCODE       9
217 #define AGENTX_WRONG_VALUE       10
218 #define AGENTX_NO_CREATION       11
219 #define AGENTX_INCONSIST_VALUE   12
220 #define AGENTX_RES_UNAVAIL       13
221 #define AGENTX_COMMIT_FAILED     14
222 #define AGENTX_UNDO_FAILED       15
223 #define AGENTX_AUTH_ERROR        16
224 #define AGENTX_NOTWRITABLE       17
225 #define AGENTX_INCONSIS_NAME     18
226 #define AGENTX_OPEN_FAILED      256
227 #define AGENTX_NOT_OPEN         257
228 #define AGENTX_IDX_WRONT_TYPE   258
229 #define AGENTX_IDX_ALREAY_ALLOC 259
230 #define AGENTX_IDX_NONEAVAIL    260
231 #define AGENTX_IDX_NOTALLOC     261
232 #define AGENTX_UNSUPP_CONTEXT   262
233 #define AGENTX_DUP_REGISTR      263
234 #define AGENTX_UNKNOWN_REG      264
235 #define AGENTX_UNKNOWN_CAPS     265
236
237
238 static const value_string resp_errors[] = {
239   { AGENTX_NO_ERROR,            "noError" },
240   { AGENTX_TOO_BIG,             "tooBig" },
241   { AGENTX_NO_SUCH_NAME,        "noSuchName" },
242   { AGENTX_BAD_VALUE,           "badValue" },
243   { AGENTX_READ_ONLY,           "readOnly" },
244   { AGENTX_GEN_ERROR,           "genErr" },
245   { AGENTX_NO_ACCESS,           "noAccess" },
246   { AGENTX_WRONG_TYPE,          "wrongType" },
247   { AGENTX_WRONG_LEN,           "wrongLength" },
248   { AGENTX_WRONG_ENCODE,        "wrongEncoding" },
249   { AGENTX_WRONG_VALUE,         "wrongValue" },
250   { AGENTX_NO_CREATION,         "noCreation" },
251   { AGENTX_INCONSIST_VALUE,     "inconsistentValue" },
252   { AGENTX_RES_UNAVAIL,         "resourceUnavailable" },
253   { AGENTX_COMMIT_FAILED,       "commitFailed" },
254   { AGENTX_UNDO_FAILED ,        "undoFailed" },
255   { AGENTX_AUTH_ERROR,          "authorizationError" },
256   { AGENTX_NOTWRITABLE,         "notWritable" },
257   { AGENTX_INCONSIS_NAME,       "inconsistentName" },
258   { AGENTX_OPEN_FAILED,         "openFailed" },
259   { AGENTX_NOT_OPEN,            "notOpen" },
260   { AGENTX_IDX_WRONT_TYPE,      "indexWrongType" },
261   { AGENTX_IDX_ALREAY_ALLOC,    "indexAlreadyAllocated" },
262   { AGENTX_IDX_NONEAVAIL,       "indexNoneAvailable" },
263   { AGENTX_IDX_NOTALLOC,        "indexNotAllocated" },
264   { AGENTX_UNSUPP_CONTEXT,      "unsupportedContext" },
265   { AGENTX_DUP_REGISTR,         "duplicateRegistration" },
266   { AGENTX_UNKNOWN_REG,         "unknownRegistration" },
267   { AGENTX_UNKNOWN_CAPS,        "unknownAgentCaps" },
268   { 0, NULL }
269 };
270 static value_string_ext resp_errors_ext = VALUE_STRING_EXT_INIT(resp_errors);
271
272 /* OID usage indicators */
273
274 enum OID_USAGE { OID_START_RANGE, OID_END_RANGE, OID_EXACT };
275
276 /* PDU Header flags */
277
278 #define INSTANCE_REGISTRATION   0x01
279 #define NEW_INDEX               0x02
280 #define ANY_INDEX               0x04
281 #define NON_DEFAULT_CONTEXT     0x08
282 #define NETWORK_BYTE_ORDER      0x10
283
284 #define OID_IS_INCLUSIVE        0x01
285
286 #define PDU_HDR_LEN     20
287 #define PADDING(x) ((((x) + 3) >> 2) << 2)
288
289 #define NORLEL(flags,var,tvb,offset) \
290         var = (flags & NETWORK_BYTE_ORDER) ? \
291                 tvb_get_ntohl(tvb, offset) : \
292                 tvb_get_letohl(tvb, offset)
293 #define NORLES(flags,var,tvb,offset) \
294         var = (flags & NETWORK_BYTE_ORDER) ? \
295                 tvb_get_ntohs(tvb, offset) : \
296                 tvb_get_letohs(tvb, offset)
297
298 static int
299 dissect_octet_string(tvbuff_t *tvb, proto_tree *tree, int offset, guint8 flags)
300 {
301         guint32 n_oct, p_noct;
302
303         NORLEL(flags, n_oct, tvb, offset);
304
305         p_noct = PADDING(n_oct);
306
307         proto_tree_add_uint(tree, hf_ostring_len, tvb, offset, 4, n_oct);
308         /*
309          * XXX - an "octet string" is not necessarily a text string, so
310          * having hf_ostring be FT_STRING is not necessarily appropriate.
311          */
312         proto_tree_add_item(tree, hf_ostring, tvb, offset + 4, n_oct, ENC_ASCII|ENC_NA);
313         return p_noct + 4;
314
315 }
316
317 /* XXX - Is there a particular reason we're not using oid_encoded2string() here? */
318 static int
319 convert_oid_to_str(guint32 *oid, int len, char* str, int slen, char prefix)
320 {
321         int i, tlen = 0;
322         if(!oid)  return 0;
323         if(!str)  return 0;
324         if(!len)  return 0;
325         if(!slen) return 0;
326         if(slen < len) return 0;
327
328         if(prefix) {
329                 tlen += g_snprintf(str, slen, ".1.3.6.1.%d", prefix);
330         }
331
332         for(i=0; i < len && tlen < slen; i++) {
333                 tlen += g_snprintf(str+tlen, slen-tlen, ".%d", oid[i]);
334         }
335         return tlen;
336 }
337
338 static int
339 dissect_object_id(tvbuff_t *tvb, proto_tree *tree, int offset, guint8 flags, enum OID_USAGE oid_usage)
340 {
341         guint8 n_subid;
342         guint8 prefix;
343         guint8 include;
344         proto_item* item;
345         proto_tree* subtree;
346         guint32 oid[2048];
347         char str_oid[2048];
348         int i;
349
350         memset(oid, '\0', sizeof(oid));
351         memset(str_oid, '\0', sizeof(str_oid));
352
353         n_subid = tvb_get_guint8(tvb, offset);
354         prefix  = tvb_get_guint8(tvb, offset + 1);
355         include = tvb_get_guint8(tvb, offset + 2);
356         tvb_get_guint8(tvb, offset + 3);
357
358         for(i=0; i<n_subid; i++) {
359                 NORLEL(flags, oid[i], tvb, (offset+4) + (i*4));
360         }
361
362         if(!convert_oid_to_str(&oid[0], n_subid, &str_oid[0], 2048, prefix))
363                 g_snprintf(&str_oid[0], 2048, "(null)");
364
365         if(tree) {
366                 const char *range = "";
367                 const char *inclusion = (include) ? " (Inclusive)" : " (Exclusive)";
368                 switch (oid_usage) {
369                         case OID_START_RANGE:   range = "(Range Start) ";       break;
370                         case OID_END_RANGE:     range = "  (Range End) ";       break;
371                         default:                inclusion = "";                 break;
372                         }
373                 item = proto_tree_add_text(tree, tvb, offset, 4 + (n_subid * 4) ,
374                                 "Object Identifier: %s%s%s", range, str_oid, inclusion);
375                 subtree = proto_item_add_subtree(item, ett_obj_ident);
376         } else
377                 return offset;
378
379         proto_tree_add_uint(subtree, hf_oid_sub, tvb, offset, 1, n_subid);
380         proto_tree_add_uint(subtree, hf_oid_prefix, tvb, offset + 1, 1, prefix);
381         proto_tree_add_boolean(subtree, hf_oid_include, tvb, offset + 2, 1, include);
382         proto_tree_add_string(subtree, hf_oid_str, tvb, offset + 4, (n_subid * 4), str_oid);
383
384         return 4 + (n_subid * 4);
385 }
386
387 static int
388 dissect_search_range(tvbuff_t *tvb, proto_tree *tree, int start_offset, guint8 flags, guint8 pdu_type)
389 {
390         int offset = start_offset;
391         offset += dissect_object_id(tvb, tree, offset, flags, (pdu_type == AGENTX_GET_PDU) ? OID_EXACT : OID_START_RANGE);
392         offset += dissect_object_id(tvb, tree, offset, flags, (pdu_type == AGENTX_GET_PDU) ? OID_EXACT : OID_END_RANGE);
393
394         return (offset - start_offset);
395 }
396
397 static int
398 dissect_val64(tvbuff_t *tvb, proto_tree *tree, int offset, guint8 flags)
399 {
400         guint encoding = (flags & NETWORK_BYTE_ORDER) ? ENC_BIG_ENDIAN : ENC_LITTLE_ENDIAN;
401
402         proto_tree_add_item(tree, hf_val64, tvb, offset, 8, encoding);
403
404         return 8;
405 }
406
407 static int
408 dissect_val32(tvbuff_t *tvb, proto_tree *tree, int offset, guint8 flags)
409 {
410         guint encoding = (flags & NETWORK_BYTE_ORDER) ? ENC_BIG_ENDIAN : ENC_LITTLE_ENDIAN;
411
412         proto_tree_add_item(tree, hf_val32, tvb, offset, 4, encoding);
413
414         return 4;
415 }
416
417 static int
418 dissect_varbind(tvbuff_t *tvb, proto_tree *tree, int offset, int len, guint8 flags)
419 {
420         guint16 vtag;
421         int tlen;
422         proto_item* item;
423         proto_tree* subtree;
424
425         NORLES(flags, vtag, tvb, offset);
426         /* 2 reserved bytes after this */
427
428         if(tree) {
429                 item = proto_tree_add_text(tree, tvb, offset, len, "Value Representation");
430                 subtree = proto_item_add_subtree(item, ett_valrep);
431         } else return len;
432
433         proto_tree_add_uint(subtree, hf_vtag, tvb, offset, 2, vtag);
434         tlen = dissect_object_id(tvb, subtree, offset + 4, flags, OID_EXACT);
435
436         switch(vtag)
437         {
438                 case  VB_OID:
439                         tlen += dissect_object_id(tvb, subtree, offset + tlen + 4, flags, OID_EXACT);
440                         break;
441
442                 case  VB_OPAQUE:
443                 case  VB_OSTR:
444                 case  VB_IPADDR:
445                         tlen += dissect_octet_string(tvb, subtree, offset + tlen + 4, flags);
446                         break;
447
448                 case  VB_TIMETICK:
449                 case  VB_COUNTER32:
450                 case  VB_INT:
451                 case  VB_GAUGE32:
452                         tlen += dissect_val32(tvb, subtree, offset + tlen + 4, flags);
453                         break;
454
455                 case  VB_COUNTER64:
456                         tlen += dissect_val64(tvb, subtree, offset + tlen + 4, flags);
457                         break;
458
459                 case  VB_NULL:
460                 case  VB_NOSUCHOBJ:
461                 case  VB_NOSUCHINST:
462                 case  VB_ENDOFMIB:
463                         break;
464         }
465         return tlen + 4;
466 }
467
468 static void
469 dissect_response_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, guint8 flags)
470 {
471         proto_item* item;
472         proto_tree* subtree;
473         guint encoding = (flags & NETWORK_BYTE_ORDER) ? ENC_BIG_ENDIAN : ENC_LITTLE_ENDIAN;
474         guint32 r_uptime;
475
476         item = proto_tree_add_text(tree, tvb, offset, len, "Response-PDU");
477         subtree = proto_item_add_subtree(item, ett_response);
478
479         NORLEL(flags, r_uptime, tvb, offset);
480         proto_tree_add_uint_format(subtree, hf_resp_uptime, tvb, offset, 4, r_uptime,
481                         "sysUptime: %s", time_msecs_to_str(wmem_packet_scope(), r_uptime));
482         proto_tree_add_item(subtree, hf_resp_error,  tvb, offset + 4, 2, encoding);
483         proto_tree_add_item(subtree, hf_resp_index,  tvb, offset + 6, 2, encoding);
484         offset += 8;
485
486         len += PDU_HDR_LEN;
487         while(len > offset) {
488                 offset += dissect_varbind(tvb, subtree, offset, len, flags);
489         }
490 }
491
492 static void
493 dissect_getnext_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, guint8 flags)
494 {
495         proto_item* item;
496         proto_tree* subtree;
497
498         item = proto_tree_add_text(tree, tvb, offset, len, "GetNext-PDU");
499         subtree = proto_item_add_subtree(item, ett_getnext);
500
501         if(flags & NON_DEFAULT_CONTEXT) {
502                 /* show context */
503                 offset += dissect_octet_string(tvb, subtree, offset, flags);
504         }
505
506         len += PDU_HDR_LEN;
507         while(len > offset) {
508                 offset += dissect_search_range(tvb, subtree, offset, flags, 0);
509         }
510 }
511
512 static void
513 dissect_get_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, guint8 flags)
514 {
515         proto_item* item;
516         proto_tree* subtree;
517
518         item = proto_tree_add_text(tree, tvb, offset, len, "Get-PDU");
519         subtree = proto_item_add_subtree(item, ett_get);
520
521         if(flags & NON_DEFAULT_CONTEXT) {
522                 /* show context */
523                 offset += dissect_octet_string(tvb, subtree, offset, flags);
524         }
525
526         len += PDU_HDR_LEN;
527         while(len > offset) {
528                 offset += dissect_search_range(tvb, subtree, offset, flags, AGENTX_GET_PDU);
529         }
530 }
531
532 static void
533 dissect_getbulk_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, guint8 flags)
534 {
535         proto_item* item;
536         proto_tree* subtree;
537         guint encoding = (flags & NETWORK_BYTE_ORDER) ? ENC_BIG_ENDIAN : ENC_LITTLE_ENDIAN;
538
539         item = proto_tree_add_text(tree, tvb, offset, len, "GetBulk-PDU");
540         subtree = proto_item_add_subtree(item, ett_getbulk);
541
542         if(flags & NON_DEFAULT_CONTEXT) {
543                 /* show context */
544                 offset += dissect_octet_string(tvb, subtree, offset, flags);
545         }
546
547         proto_tree_add_item(subtree, hf_gbulk_nrepeat,  tvb, offset, 2, encoding);
548         proto_tree_add_item(subtree, hf_gbulk_mrepeat,  tvb, offset + 2, 2, encoding);
549         offset+=4;
550
551         while(len >= offset) {
552                 offset += dissect_search_range(tvb, subtree, offset, flags, 0);
553         }
554 }
555
556 static int
557 dissect_open_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, guint8 flags)
558 {
559         proto_item* item;
560         proto_tree* subtree;
561         guint8 timeout;
562
563         item = proto_tree_add_text(tree, tvb, offset, len, "Open-PDU");
564         subtree = proto_item_add_subtree(item, ett_open);
565
566         timeout = tvb_get_guint8(tvb, offset);
567         tvb_get_ntoh24(tvb, offset + 1);
568
569         proto_tree_add_uint(subtree, hf_open_timeout, tvb, offset, 1, timeout);
570         offset+=4;
571
572         /* Search Range */
573         offset += dissect_object_id(tvb, subtree, offset, flags, OID_EXACT);
574
575         /* Octet string */
576         offset += dissect_octet_string(tvb, subtree, offset, flags);
577         return offset;
578 }
579
580 static int
581 dissect_close_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len)
582 {
583         proto_item* item;
584         proto_tree* subtree;
585         guint8 reason;
586
587         item = proto_tree_add_text(tree, tvb, offset, len, "Close-PDU");
588         subtree = proto_item_add_subtree(item, ett_close);
589
590         reason = tvb_get_guint8(tvb, offset);
591         tvb_get_ntoh24(tvb, offset + 1);
592
593         proto_tree_add_uint(subtree, hf_close_reason, tvb, offset, 1, reason);
594         offset+=4;
595         return offset;
596 }
597
598
599 static int
600 dissect_register_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, guint8 flags)
601 {
602
603         proto_item* item;
604         proto_tree* subtree;
605         guint encoding = (flags & NETWORK_BYTE_ORDER) ? ENC_BIG_ENDIAN : ENC_LITTLE_ENDIAN;
606
607         item = proto_tree_add_text(tree, tvb, offset, len, "Register-PDU");
608         subtree = proto_item_add_subtree(item, ett_register);
609
610         if(flags & NON_DEFAULT_CONTEXT) {
611                 /* show context */
612                 offset += dissect_octet_string(tvb, subtree, offset, flags);
613         }
614
615         proto_tree_add_item(subtree, hf_reg_timeout, tvb, offset, 1, encoding);
616         proto_tree_add_item(subtree, hf_reg_prio, tvb, offset+1, 1, encoding);
617         proto_tree_add_item(subtree, hf_reg_rsid, tvb, offset+2, 1, encoding);
618         offset+=4;
619
620         /* Region */
621
622         offset += dissect_object_id(tvb, subtree, offset, flags, OID_EXACT);
623
624         len += PDU_HDR_LEN;
625         if(len > offset) {
626                 /* Upper bound (opt) */
627                 proto_tree_add_item(subtree, hf_reg_ubound, tvb, offset, 4, encoding);
628                 offset += 4;
629         }
630         return offset;
631 }
632
633
634 static int
635 dissect_unregister_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, guint8 flags)
636 {
637         proto_item* item;
638         proto_tree* subtree;
639         guint encoding = (flags & NETWORK_BYTE_ORDER) ? ENC_BIG_ENDIAN : ENC_LITTLE_ENDIAN;
640
641         item = proto_tree_add_text(tree, tvb, offset, len, "Unregister-PDU");
642         subtree = proto_item_add_subtree(item, ett_unregister);
643
644         if(flags & NON_DEFAULT_CONTEXT) {
645                 /* show context */
646                 offset += dissect_octet_string(tvb, subtree, offset, flags);
647         }
648
649         proto_tree_add_item(subtree, hf_unreg_timeout, tvb, offset, 1, encoding);
650         proto_tree_add_item(subtree, hf_unreg_prio, tvb, offset+1, 1, encoding);
651         proto_tree_add_item(subtree, hf_unreg_rsid, tvb, offset+2, 1, encoding);
652         offset+=4;
653
654         /* Region */
655         offset += dissect_object_id(tvb, subtree, offset, flags, OID_EXACT);
656
657         len += PDU_HDR_LEN;
658         if(len > offset) {
659                 /* Upper bound (opt) */
660                 proto_tree_add_item(subtree, hf_unreg_ubound, tvb, offset, 4, encoding);
661                 offset += 4;
662         }
663
664         return offset;
665 }
666
667 static void
668 dissect_testset_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, guint8 flags)
669 {
670         proto_item* item;
671         proto_tree* subtree;
672
673         item = proto_tree_add_text(tree, tvb, offset, len, "Testset-PDU");
674         subtree = proto_item_add_subtree(item, ett_testset);
675
676         if(flags & NON_DEFAULT_CONTEXT) {
677                 /* show context */
678                 offset += dissect_octet_string(tvb, subtree, offset, flags);
679         }
680
681         while(len > offset) {
682                 offset += dissect_varbind(tvb, subtree, offset, len, flags);
683         }
684 }
685
686 static void
687 dissect_notify_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, guint8 flags)
688 {
689         proto_item* item;
690         proto_tree* subtree;
691
692         item = proto_tree_add_text(tree, tvb, offset, len, "Notify-PDU");
693         subtree = proto_item_add_subtree(item, ett_notify);
694
695         if(flags & NON_DEFAULT_CONTEXT) {
696                 /* show context */
697                 offset += dissect_octet_string(tvb, subtree, offset, flags);
698         }
699
700         while(len > offset) {
701                 offset += dissect_varbind(tvb, subtree, offset, len, flags);
702         }
703 }
704
705 static int
706 dissect_ping_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, guint8 flags)
707 {
708         proto_item* item;
709         proto_tree* subtree;
710
711         item = proto_tree_add_text(tree, tvb, offset, len, "Ping-PDU");
712         subtree = proto_item_add_subtree(item, ett_ping);
713
714         if(flags & NON_DEFAULT_CONTEXT) {
715                 /* show context */
716                 offset += dissect_octet_string(tvb, subtree, offset, flags);
717         }
718         return offset;
719 }
720
721 static void
722 dissect_idx_alloc_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, guint8 flags)
723 {
724         proto_item* item;
725         proto_tree* subtree;
726
727         item = proto_tree_add_text(tree, tvb, offset, len, "IndexAllocate-PDU");
728         subtree = proto_item_add_subtree(item, ett_idxalloc);
729
730         if(flags & NON_DEFAULT_CONTEXT) {
731                 /* show context */
732                 offset += dissect_octet_string(tvb, subtree, offset, flags);
733         }
734
735         while(len > offset) {
736                 offset += dissect_varbind(tvb, subtree, offset, len, flags);
737         }
738 }
739
740
741 static void
742 dissect_idx_dealloc_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, guint8 flags)
743 {
744         proto_item* item;
745         proto_tree* subtree;
746
747         item = proto_tree_add_text(tree, tvb, offset, len, "IndexDeallocate-PDU");
748         subtree = proto_item_add_subtree(item, ett_idxdalloc);
749
750         if(flags & NON_DEFAULT_CONTEXT) {
751                 /* show context */
752                 offset += dissect_octet_string(tvb, subtree, offset, flags);
753         }
754
755         while(len > offset) {
756                 offset += dissect_varbind(tvb, subtree, offset, len, flags);
757         }
758 }
759
760 static int
761 dissect_add_caps_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, guint8 flags)
762 {
763         proto_item* item;
764         proto_tree* subtree;
765
766         item = proto_tree_add_text(tree, tvb, offset, len, "AddAgentCaps-PDU");
767         subtree = proto_item_add_subtree(item, ett_addcap);
768
769         if(flags & NON_DEFAULT_CONTEXT) {
770                 /* show context */
771                 offset += dissect_octet_string(tvb, subtree, offset, flags);
772         }
773
774         offset += dissect_object_id(tvb, subtree, offset, flags, OID_EXACT);
775
776         offset += dissect_octet_string(tvb, subtree, offset, flags);
777
778         return offset;
779 }
780
781 static int
782 dissect_rem_caps_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, guint8 flags)
783 {
784         proto_item* item;
785         proto_tree* subtree;
786
787         item = proto_tree_add_text(tree, tvb, offset, len, "RemoveAgentCaps-PDU");
788         subtree = proto_item_add_subtree(item, ett_remcap);
789
790         if(flags & NON_DEFAULT_CONTEXT) {
791                 /* show context */
792                 offset += dissect_octet_string(tvb, subtree, offset, flags);
793         }
794
795         offset += dissect_object_id(tvb, subtree, offset, flags, OID_EXACT);
796
797         return offset;
798 }
799
800
801 static guint
802 get_agentx_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
803 {
804         guint8  flags;
805         guint32 plen;
806
807         /*
808          * Get the payload length.
809          */
810         flags = tvb_get_guint8(tvb, offset + 2);
811         NORLEL(flags, plen, tvb, offset + 16);
812
813         /*
814          * Arbitrarily limit it to 2^24, so we don't have to worry about
815          * overflow.
816          */
817         if (plen > 0xFFFFFF)
818                 plen = 0xFFFFFF;
819
820         /*
821          * That length doesn't include the header; add that in.
822          */
823         return plen + 20;
824 }
825
826 static int
827 dissect_agentx_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data _U_)
828 {
829         int offset = 0;
830         proto_tree* agentx_tree, *pdu_hdr_tree, *flags_tree;
831         proto_item* pdu_item , *t_item;
832         guint8 version;
833         guint8 type;
834         guint8 flags;
835         guint32 session_id;
836         guint32 trans_id;
837         guint32 packet_id;
838         guint32 payload_len;
839
840         version = tvb_get_guint8(tvb, 0); offset+=1;
841         type = tvb_get_guint8(tvb, 1); offset+=1;
842         flags = tvb_get_guint8(tvb, 2); offset+=1;
843         /* skip reserved byte */
844         offset+=1;
845
846         NORLEL(flags, session_id, tvb, 4); offset+=4;
847         NORLEL(flags, trans_id, tvb, 8); offset+=4;
848         NORLEL(flags, packet_id, tvb, 12); offset+=4;
849         NORLEL(flags, payload_len, tvb, 16); offset+=4;
850
851         col_set_str(pinfo->cinfo, COL_PROTOCOL, "AgentX");
852
853         col_add_fstr(pinfo->cinfo, COL_INFO, "%s: sid=%d, tid=%d, packid=%d, plen=%d",
854                      val_to_str_ext_const(type, &type_values_ext, "unknown"),
855                      session_id, trans_id, packet_id, payload_len);
856
857
858         if(!tree)
859                 return 0;
860
861         /*t_item = proto_tree_add_item(tree, proto_agentx, tvb, 0, -1, ENC_NA);*/
862         t_item = proto_tree_add_protocol_format(tree, proto_agentx, tvb, 0, -1,
863                         "Agent Extensibility (AgentX) Protocol: %s, sid=%d, tid=%d, packid=%d, plen=%d",
864                         val_to_str_ext_const(type, &type_values_ext, "unknown"),
865                         session_id, trans_id, packet_id, payload_len);
866         agentx_tree = proto_item_add_subtree(t_item, ett_agentx);
867
868         pdu_item = proto_tree_add_text(agentx_tree, tvb, 0, PDU_HDR_LEN, "PDU Header: Type[%u], len=%d, sid=%d, tid=%d, packid=%d",
869                         (char)type, payload_len, session_id, trans_id, packet_id);
870
871         pdu_hdr_tree = proto_item_add_subtree(pdu_item, ett_pdu_hdr);
872
873         proto_tree_add_uint(pdu_hdr_tree, hf_version, tvb, 0, 1, version);
874         proto_tree_add_uint(pdu_hdr_tree, hf_type, tvb, 1, 1, type);
875
876         t_item = proto_tree_add_text(pdu_hdr_tree, tvb, 2, 1, "Flags: 0x%02x", flags);
877         flags_tree = proto_item_add_subtree(t_item, ett_flags);
878         proto_tree_add_boolean(flags_tree, hf_flags_register,   tvb, 2, 1, flags);
879         proto_tree_add_boolean(flags_tree, hf_flags_newindex,   tvb, 2, 1, flags);
880         proto_tree_add_boolean(flags_tree, hf_flags_anyindex,   tvb, 2, 1, flags);
881         proto_tree_add_boolean(flags_tree, hf_flags_context,    tvb, 2, 1, flags);
882         proto_tree_add_boolean(flags_tree, hf_flags_byteorder,  tvb, 2, 1, flags);
883
884         proto_tree_add_uint(pdu_hdr_tree, hf_session_id, tvb, 4, 4, session_id);
885         proto_tree_add_uint(pdu_hdr_tree, hf_trans_id, tvb, 8, 4, trans_id);
886         proto_tree_add_uint(pdu_hdr_tree, hf_packet_id, tvb, 12, 4, packet_id);
887         proto_tree_add_uint(pdu_hdr_tree, hf_payload_len, tvb, 16, 4, payload_len);
888
889         switch(type) {
890                 case AGENTX_OPEN_PDU:
891                 dissect_open_pdu(tvb, agentx_tree, offset, payload_len, flags);
892                 break;
893
894                 case AGENTX_CLOSE_PDU:
895                 dissect_close_pdu(tvb, agentx_tree, offset, payload_len);
896                 break;
897
898                 case AGENTX_REGISTER_PDU:
899                 dissect_register_pdu(tvb, agentx_tree, offset, payload_len, flags);
900                 break;
901
902                 case AGENTX_UNREGISTER_PDU:
903                 dissect_unregister_pdu(tvb, agentx_tree, offset, payload_len, flags);
904                 break;
905
906                 case AGENTX_GET_PDU:
907                 dissect_get_pdu(tvb, agentx_tree, offset, payload_len, flags);
908                 break;
909
910                 case AGENTX_GETNEXT_PDU:
911                 dissect_getnext_pdu(tvb, agentx_tree, offset, payload_len, flags);
912                 break;
913
914                 case AGENTX_GETBULK_PDU:
915                 dissect_getbulk_pdu(tvb, agentx_tree, offset, payload_len, flags);
916                 break;
917
918                 case AGENTX_TESTSET_PDU:
919                 dissect_testset_pdu(tvb, agentx_tree, offset, payload_len, flags);
920                 break;
921
922                 case AGENTX_COMMITSET_PDU:
923                 case AGENTX_UNDOSET_PDU:
924                 case AGENTX_CLEANUPSET_PDU:
925                         /* there is no parameters */
926                 break;
927
928                 case AGENTX_NOTIFY_PDU:
929                 dissect_notify_pdu(tvb, agentx_tree, offset, payload_len, flags);
930                 break;
931
932                 case AGENTX_PING_PDU:
933                 dissect_ping_pdu(tvb, agentx_tree, offset, payload_len, flags);
934                 break;
935
936                 case AGENTX_INDEX_ALLOC_PDU:
937                 dissect_idx_alloc_pdu(tvb, agentx_tree, offset, payload_len, flags);
938                 break;
939
940                 case AGENTX_INDEX_DEALLOC_PDU:
941                 dissect_idx_dealloc_pdu(tvb, agentx_tree, offset, payload_len, flags);
942                 break;
943
944                 case AGENTX_ADD_AGENT_CAPS_PDU:
945                 dissect_add_caps_pdu(tvb, agentx_tree, offset, payload_len, flags);
946                 break;
947
948                 case AGENTX_REM_AGENT_CAPS_PDU:
949                 dissect_rem_caps_pdu(tvb, agentx_tree, offset, payload_len, flags);
950                 break;
951
952                 case AGENTX_RESPONSE_PDU:
953                 dissect_response_pdu(tvb, agentx_tree, offset, payload_len, flags);
954                 break;
955         }
956
957     return tvb_length(tvb);
958 }
959
960 static int
961 dissect_agentx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void* data)
962 {
963         tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 20, get_agentx_pdu_len,
964                          dissect_agentx_pdu, data);
965         return tvb_length(tvb);
966 }
967
968 static const true_false_string tfs_agentx_include       = { "Yes",                      "No"    };
969 static const true_false_string tfs_agentx_register      = { "Yes",                      "No"    };
970 static const true_false_string tfs_agentx_newindex      = { "Yes",                      "No"    };
971 static const true_false_string tfs_agentx_anyindex      = { "Yes",                      "No"    };
972 static const true_false_string tfs_agentx_context       = { "Provided",                 "None"  };
973 static const true_false_string tfs_agentx_byteorder     = { "MSB (network order)",      "LSB"   };
974
975 void
976 proto_register_agentx(void)
977 {
978         static hf_register_info hf[] = {
979
980                 { &hf_version,
981                   { "Version", "agentx.version", FT_UINT8, BASE_DEC, NULL, 0x0,
982                     "header version", HFILL }},
983
984                 { &hf_type,
985                   { "Type", "agentx.type", FT_UINT8, BASE_DEC | BASE_EXT_STRING, &type_values_ext, 0x0,
986                     "header type", HFILL }},
987
988 #if 0
989                 { &hf_flags,
990                   { "Flags", "agentx.flags", FT_UINT8, BASE_DEC, NULL, 0x0,
991                     "header type", HFILL }},
992 #endif
993
994                 { &hf_flags_register,
995                   { "Register", "agentx.flags.register", FT_BOOLEAN, 8, TFS(&tfs_agentx_register),
996                     INSTANCE_REGISTRATION, "Instance Registration",  HFILL }},
997
998                 { &hf_flags_newindex,
999                   { "New Index", "agentx.flags.newindex", FT_BOOLEAN, 8, TFS(&tfs_agentx_newindex),
1000                     NEW_INDEX, "New Index Requested",  HFILL }},
1001
1002                 { &hf_flags_anyindex,
1003                   { "Any Index", "agentx.flags.anyindex", FT_BOOLEAN, 8, TFS(&tfs_agentx_anyindex),
1004                     ANY_INDEX, "Any Index Requested",  HFILL }},
1005
1006                 { &hf_flags_context,
1007                   { "Non-default Context", "agentx.flags.context", FT_BOOLEAN, 8, TFS(&tfs_agentx_context),
1008                     NON_DEFAULT_CONTEXT, NULL,  HFILL }},
1009
1010                 { &hf_flags_byteorder,
1011                   { "Byte Order", "agentx.flags.byteorder", FT_BOOLEAN, 8, TFS(&tfs_agentx_byteorder),
1012                     NETWORK_BYTE_ORDER, NULL,  HFILL }},
1013
1014                 { &hf_session_id,
1015                   { "sessionID", "agentx.session_id", FT_UINT32, BASE_DEC, NULL, 0x0,
1016                     "Session ID", HFILL }},
1017
1018                 { &hf_trans_id,
1019                   { "TransactionID", "agentx.transaction_id", FT_UINT32, BASE_DEC, NULL, 0x0,
1020                     "Transaction ID", HFILL }},
1021
1022                 { &hf_packet_id,
1023                   { "PacketID", "agentx.packet_id", FT_UINT32, BASE_DEC, NULL, 0x0,
1024                     "Packet ID", HFILL }},
1025
1026                 { &hf_payload_len,
1027                   { "Payload length", "agentx.payload_len", FT_UINT32, BASE_DEC, NULL, 0x0,
1028                     NULL, HFILL }},
1029
1030                 { &hf_ostring,
1031                   { "Octet String", "agentx.ostring", FT_STRING, BASE_NONE, NULL, 0x0,
1032                     NULL, HFILL }},
1033
1034                 { &hf_ostring_len,
1035                   { "OString len", "agentx.ostring_len", FT_UINT32, BASE_DEC, NULL, 0x0,
1036                     "Octet String Length", HFILL }},
1037
1038                 { &hf_oid_sub,
1039                   { "Number subids", "agentx.n_subid", FT_UINT8, BASE_DEC, NULL, 0x0,
1040                     NULL, HFILL }},
1041
1042                 { &hf_oid_prefix,
1043                   { "OID prefix", "agentx.oid_prefix", FT_UINT8, BASE_DEC, NULL, 0x0,
1044                     NULL, HFILL }},
1045
1046                 { &hf_oid_include,
1047                   { "OID include", "agentx.oid_include", FT_BOOLEAN, 8, TFS(&tfs_agentx_include),
1048                     OID_IS_INCLUSIVE, NULL, HFILL }},
1049
1050                 { &hf_oid_str,
1051                   { "OID", "agentx.oid", FT_STRING, BASE_NONE, NULL, 0x0,
1052                     NULL, HFILL }},
1053
1054                 { &hf_resp_uptime,
1055                   { "sysUpTime", "agentx.r.uptime", FT_UINT32, BASE_DEC, NULL, 0x0,
1056                     NULL, HFILL }},
1057
1058                 { &hf_resp_error,
1059                   { "Resp. error", "agentx.r.error", FT_UINT16, BASE_DEC | BASE_EXT_STRING, &resp_errors_ext, 0x0,
1060                     "response error", HFILL }},
1061
1062                 { &hf_resp_index,
1063                   { "Resp. index", "agentx.r.index", FT_UINT16, BASE_DEC, NULL, 0x0,
1064                     "response index", HFILL }},
1065
1066                 { &hf_vtag,
1067                   { "Variable type", "agentx.v.tag", FT_UINT16, BASE_DEC | BASE_EXT_STRING, &vtag_values_ext, 0x0,
1068                     "vtag", HFILL }},
1069
1070                 { &hf_val32,
1071                   { "Value(32)", "agentx.v.val32", FT_UINT32, BASE_DEC, NULL, 0x0,
1072                     "val32", HFILL }},
1073
1074                 { &hf_val64,
1075                   { "Value(64)", "agentx.v.val64", FT_UINT64, BASE_DEC, NULL, 0x0,
1076                     "val64", HFILL }},
1077
1078                 { &hf_open_timeout,
1079                   { "Timeout", "agentx.o.timeout", FT_UINT8, BASE_DEC, NULL, 0x0,
1080                     "open timeout", HFILL }},
1081
1082                 { &hf_close_reason,
1083                   { "Reason", "agentx.c.reason", FT_UINT8, BASE_DEC, VALS(close_reasons), 0x0,
1084                     "close reason", HFILL }},
1085
1086                 { &hf_reg_timeout,
1087                   { "Timeout", "agentx.r.timeout", FT_UINT8, BASE_DEC, NULL, 0x0,
1088                     "Register timeout", HFILL }},
1089
1090                 { &hf_reg_prio,
1091                   { "Priority", "agentx.r.priority", FT_UINT8, BASE_DEC, NULL, 0x0,
1092                     "Register Priority", HFILL }},
1093
1094                 { &hf_reg_rsid,
1095                   { "Range_subid", "agentx.r.range_subid", FT_UINT8, BASE_DEC, NULL, 0x0,
1096                     "Register range_subid", HFILL }},
1097
1098                 { &hf_reg_ubound,
1099                   { "Upper bound", "agentx.r.upper_bound", FT_UINT32, BASE_DEC, NULL, 0x0,
1100                     "Register upper bound", HFILL }},
1101
1102                 { &hf_unreg_timeout,
1103                   { "Timeout", "agentx.u.timeout", FT_UINT8, BASE_DEC, NULL, 0x0,
1104                     "Unregister timeout", HFILL }},
1105
1106                 { &hf_unreg_prio,
1107                   { "Priority", "agentx.u.priority", FT_UINT8, BASE_DEC, NULL, 0x0,
1108                     "Unregister Priority", HFILL }},
1109
1110                 { &hf_unreg_rsid,
1111                   { "Range_subid", "agentx.u.range_subid", FT_UINT8, BASE_DEC, NULL, 0x0,
1112                     "Unregister range_subid", HFILL }},
1113
1114                 { &hf_unreg_ubound,
1115                   { "Upper bound", "agentx.u.upper_bound", FT_UINT32, BASE_DEC, NULL, 0x0,
1116                     "Register upper bound", HFILL }},
1117
1118                 { &hf_gbulk_nrepeat,
1119                   { "Repeaters", "agentx.gb.nrepeat", FT_UINT16, BASE_DEC, NULL, 0x0,
1120                     "getBulk Num. repeaters", HFILL }},
1121
1122                 { &hf_gbulk_mrepeat,
1123                   { "Max Repetition", "agentx.gb.mrepeat", FT_UINT16, BASE_DEC, NULL, 0x0,
1124                     "getBulk Max repetition", HFILL }},
1125
1126
1127                 /* Add more fields here */
1128
1129         };
1130
1131         static gint *ett[] = {
1132                 &ett_agentx,
1133                 &ett_pdu_hdr,
1134                 &ett_get,
1135                 &ett_getnext,
1136                 &ett_search_range,
1137                 &ett_obj_ident,
1138                 &ett_response,
1139                 &ett_valrep,
1140                 &ett_open,
1141                 &ett_close,
1142                 &ett_register,
1143                 &ett_unregister,
1144                 &ett_getbulk,
1145                 &ett_testset,
1146                 &ett_commitset,
1147                 &ett_undoset,
1148                 &ett_cleanupset,
1149                 &ett_notify,
1150                 &ett_ping,
1151                 &ett_idxalloc,
1152                 &ett_idxdalloc,
1153                 &ett_addcap,
1154                 &ett_remcap,
1155                 &ett_flags,
1156         };
1157
1158
1159         module_t *agentx_module;
1160
1161         proto_agentx = proto_register_protocol("AgentX",
1162                                                "AgentX", "agentx");
1163
1164         proto_register_field_array(proto_agentx, hf, array_length(hf));
1165         proto_register_subtree_array(ett, array_length(ett));
1166
1167         agentx_module = prefs_register_protocol(proto_agentx, proto_reg_handoff_agentx);
1168
1169         prefs_register_uint_preference(agentx_module, "tcp.agentx_port",
1170                                        "AgentX listener TCP Port",
1171                                        "Set the TCP port for AgentX"
1172                                        "(if other than the default of 705)",
1173                                        10, &global_agentx_tcp_port);
1174 }
1175
1176 /* The registration hand-off routine */
1177 void
1178 proto_reg_handoff_agentx(void)
1179 {
1180         static gboolean agentx_prefs_initialized = FALSE;
1181         static dissector_handle_t agentx_handle;
1182         static guint agentx_tcp_port;
1183
1184         if(!agentx_prefs_initialized) {
1185                 agentx_handle = new_create_dissector_handle(dissect_agentx, proto_agentx);
1186                 agentx_prefs_initialized = TRUE;
1187         }
1188         else {
1189                 dissector_delete_uint("tcp.port", agentx_tcp_port, agentx_handle);
1190         }
1191
1192         agentx_tcp_port = global_agentx_tcp_port;
1193         dissector_add_uint("tcp.port", agentx_tcp_port, agentx_handle);
1194 }