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