0d7e45df4fb0d285d87e106f716f55e70ac1b57f
[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
274
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 PDU_HDR_LEN     20
285 #define PADDING(x) ((((x) + 3) >> 2) << 2)
286
287 #define NORLEL(flags,var,tvb,offset) \
288         var = (flags & NETWORK_BYTE_ORDER) ? \
289                 tvb_get_ntohl(tvb, offset) : \
290                 tvb_get_letohl(tvb, offset)
291 #define NORLES(flags,var,tvb,offset) \
292         var = (flags & NETWORK_BYTE_ORDER) ? \
293                 tvb_get_ntohs(tvb, offset) : \
294                 tvb_get_letohs(tvb, offset)
295
296 static int
297 dissect_octet_string(tvbuff_t *tvb, proto_tree *tree, int offset, char flags)
298 {
299         guint32 n_oct, p_noct;
300         char context[1024];
301
302         NORLEL(flags, n_oct, tvb, offset);
303
304         p_noct = PADDING(n_oct);
305         if (n_oct >= 1024)
306                 THROW(ReportedBoundsError);
307         tvb_get_nstringz(tvb, offset + 4, n_oct, context);
308         context[n_oct]='\0';
309
310         proto_tree_add_uint(tree, hf_ostring_len, tvb, offset, 4, n_oct);
311         proto_tree_add_string(tree, hf_ostring, tvb, offset + 4, n_oct, context);
312         return p_noct + 4;
313
314 }
315
316 /* XXX - Is there a particular reason we're not using oid_encoded2string() here? */
317 static int
318 convert_oid_to_str(guint32 *oid, int len, char* str, int slen, char prefix)
319 {
320         int i, tlen = 0;
321         if(!oid) return 0;
322         if(!str) return 0;
323         if(!len) return 0;
324         if(!slen) return 0;
325         if(slen < len) return 0;
326
327         if(prefix) {
328                 tlen += g_snprintf(str, slen, ".1.3.6.1.%d", prefix);
329         }
330
331         for(i=0; i < len && tlen < slen; i++) {
332                 tlen += g_snprintf(str+tlen, slen-tlen, ".%d", oid[i]);
333         }
334         return tlen;
335 }
336
337 static int
338 dissect_object_id(tvbuff_t *tvb, proto_tree *tree, int offset, char flags)
339 {
340         guint8 n_subid;
341         guint8 prefix;
342         guint8 include;
343         proto_item* item;
344         proto_tree* subtree;
345         guint32 oid[2048];
346         char str_oid[2048];
347         int i, slen;
348
349         memset(oid, '\0', sizeof(oid));
350         memset(str_oid, '\0', sizeof(str_oid));
351
352         n_subid = tvb_get_guint8(tvb, offset);
353         prefix = tvb_get_guint8(tvb, offset + 1);
354         include = tvb_get_guint8(tvb, offset + 2);
355         tvb_get_guint8(tvb, offset + 3);
356
357         for(i=0; i<n_subid; i++) {
358                 NORLEL(flags, oid[i], tvb, (offset+4) + (i*4));
359         }
360
361         if(!(slen = convert_oid_to_str(&oid[0], n_subid, &str_oid[0], 2048, prefix)))
362                 slen = g_snprintf(&str_oid[0], 2048, "(null)");
363
364         if(tree) {
365                 item = proto_tree_add_text(tree, tvb, offset, 4 + (n_subid * 4) ,
366                                 "Object Identifier: (%s) %s", (include) ? "Start" : "End" , str_oid);
367                 subtree = proto_item_add_subtree(item, ett_obj_ident);
368         } else return offset;
369
370         proto_tree_add_uint(subtree, hf_oid_sub, tvb, offset, 1, n_subid);
371         proto_tree_add_uint(subtree, hf_oid_prefix, tvb, offset + 1, 1, prefix);
372         proto_tree_add_uint(subtree, hf_oid_include, tvb, offset + 2, 1, include);
373         proto_tree_add_string(subtree, hf_oid_str, tvb, offset + 4, slen, str_oid);
374
375         return 4 + (n_subid * 4);
376 }
377
378 static int
379 dissect_search_range(tvbuff_t *tvb, proto_tree *tree, int start_offset, char flags)
380 {
381         int offset = start_offset;
382         offset += dissect_object_id(tvb, tree, offset, flags);
383         offset += dissect_object_id(tvb, tree, offset, flags);
384
385         return (offset - start_offset);
386 }
387
388 static int
389 dissect_val64(tvbuff_t *tvb, proto_tree *tree, int offset, char flags)
390 {
391         gboolean little_endian = !(flags & NETWORK_BYTE_ORDER);
392
393         proto_tree_add_item(tree, hf_val64, tvb, offset, 8, little_endian);
394
395         return 8;
396 }
397
398 static int
399 dissect_val32(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_val32, tvb, offset, 4, little_endian);
404
405         return 4;
406 }
407
408 static int
409 dissect_varbind(tvbuff_t *tvb, proto_tree *tree, int offset, int len, char flags)
410 {
411         guint16 vtag;
412         int tlen;
413         proto_item* item;
414         proto_tree* subtree;
415
416         NORLES(flags, vtag, tvb, offset);
417         /* 2 reserved bytes after this */
418
419         if(tree) {
420                 item = proto_tree_add_text(tree, tvb, offset, len, "Value Representation");
421                 subtree = proto_item_add_subtree(item, ett_valrep);
422         } else return len;
423
424         proto_tree_add_uint(subtree, hf_vtag, tvb, offset, 2, vtag);
425         tlen = dissect_object_id(tvb, subtree, offset + 4, flags);
426
427         switch(vtag)
428         {
429                 case  VB_OID:
430                         tlen += dissect_object_id(tvb, subtree, offset + tlen + 4, flags);
431                         break;
432
433                 case  VB_OPAQUE:
434                 case  VB_OSTR:
435                 case  VB_IPADDR:
436                         tlen += dissect_octet_string(tvb, subtree, offset + tlen + 4, flags);
437                         break;
438
439                 case  VB_TIMETICK:
440                 case  VB_COUNTER32:
441                 case  VB_INT:
442                 case  VB_GAUGE32:
443                         tlen += dissect_val32(tvb, subtree, offset + tlen + 4, flags);
444                         break;
445
446                 case  VB_COUNTER64:
447                         tlen += dissect_val64(tvb, subtree, offset + tlen + 4, flags);
448                         break;
449
450                 case  VB_NULL:
451                 case  VB_NOSUCHOBJ:
452                 case  VB_NOSUCHINST:
453                 case  VB_ENDOFMIB:
454                         break;
455         }
456         return tlen + 4;
457 }
458
459 static void
460 dissect_response_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, char flags)
461 {
462         proto_item* item;
463         proto_tree* subtree;
464         gboolean little_endian = !(flags & NETWORK_BYTE_ORDER);
465         guint32 r_uptime;
466
467         item = proto_tree_add_text(tree, tvb, offset, len, "Response-PDU");
468         subtree = proto_item_add_subtree(item, ett_response);
469
470         r_uptime = little_endian ? \
471             tvb_get_letohl(tvb, offset) : tvb_get_ntohl(tvb, offset);
472
473         proto_tree_add_uint_format(subtree, hf_resp_uptime, tvb, offset, 4, r_uptime,
474                         "sysUptime: %s", time_msecs_to_str(r_uptime));
475         proto_tree_add_item(subtree, hf_resp_error,  tvb, offset + 4, 2, little_endian);
476         proto_tree_add_item(subtree, hf_resp_index,  tvb, offset + 6, 2, little_endian);
477         offset += 8;
478
479         len += PDU_HDR_LEN;
480         while(len > offset) {
481                 offset += dissect_varbind(tvb, subtree, offset, len, flags);
482         }
483 }
484
485 static void
486 dissect_getnext_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, char flags)
487 {
488         proto_item* item;
489         proto_tree* subtree;
490
491         item = proto_tree_add_text(tree, tvb, offset, len, "GetNext-PDU");
492         subtree = proto_item_add_subtree(item, ett_getnext);
493
494         if(flags & NON_DEFAULT_CONTEXT) {
495                 /* show context */
496                 offset += dissect_octet_string(tvb, subtree, offset, flags);
497         }
498
499         len += PDU_HDR_LEN;
500         while(len > offset) {
501                 offset += dissect_search_range(tvb, subtree, offset, flags);
502         }
503 }
504
505 static void
506 dissect_get_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, char flags)
507 {
508         proto_item* item;
509         proto_tree* subtree;
510
511         item = proto_tree_add_text(tree, tvb, offset, len, "Get-PDU");
512         subtree = proto_item_add_subtree(item, ett_get);
513
514         if(flags & NON_DEFAULT_CONTEXT) {
515                 /* show context */
516                 offset += dissect_octet_string(tvb, subtree, offset, flags);
517         }
518
519         len += PDU_HDR_LEN;
520         while(len > offset) {
521                 offset += dissect_search_range(tvb, subtree, offset, flags);
522         }
523 }
524
525 static void
526 dissect_getbulk_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, char flags)
527 {
528         proto_item* item;
529         proto_tree* subtree;
530         gboolean little_endian = !(flags & NETWORK_BYTE_ORDER);
531
532         item = proto_tree_add_text(tree, tvb, offset, len, "GetBulk-PDU");
533         subtree = proto_item_add_subtree(item, ett_getbulk);
534
535         if(flags & NON_DEFAULT_CONTEXT) {
536                 /* show context */
537                 offset += dissect_octet_string(tvb, subtree, offset, flags);
538         }
539
540         proto_tree_add_item(subtree, hf_gbulk_nrepeat,  tvb, offset, 2, little_endian);
541         proto_tree_add_item(subtree, hf_gbulk_mrepeat,  tvb, offset + 2, 2, little_endian);
542         offset+=4;
543
544         while(len >= offset) {
545                 offset += dissect_search_range(tvb, subtree, offset, flags);
546         }
547 }
548
549 static void
550 dissect_open_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, char flags)
551 {
552         proto_item* item;
553         proto_tree* subtree;
554         guint8 timeout;
555
556         item = proto_tree_add_text(tree, tvb, offset, len, "Open-PDU");
557         subtree = proto_item_add_subtree(item, ett_open);
558
559         timeout = tvb_get_guint8(tvb, offset);
560         tvb_get_ntoh24(tvb, offset + 1);
561
562         proto_tree_add_uint(subtree, hf_open_timeout, tvb, offset, 1, timeout);
563         offset+=4;
564
565         /* Search Range */
566         offset += dissect_object_id(tvb, subtree, offset, flags);
567
568         /* Octet string */
569         offset += dissect_octet_string(tvb, subtree, offset, flags);
570 }
571
572 static void
573 dissect_close_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len)
574 {
575         proto_item* item;
576         proto_tree* subtree;
577         guint8 reason;
578
579         item = proto_tree_add_text(tree, tvb, offset, len, "Close-PDU");
580         subtree = proto_item_add_subtree(item, ett_close);
581
582         reason = tvb_get_guint8(tvb, offset);
583         tvb_get_ntoh24(tvb, offset + 1);
584
585         proto_tree_add_uint(subtree, hf_close_reason, tvb, offset, 1, reason);
586         offset+=4;
587 }
588
589
590 static void
591 dissect_register_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, char flags)
592 {
593
594         proto_item* item;
595         proto_tree* subtree;
596         gboolean little_endian = !(flags & NETWORK_BYTE_ORDER);
597
598         item = proto_tree_add_text(tree, tvb, offset, len, "Register-PDU");
599         subtree = proto_item_add_subtree(item, ett_register);
600
601         if(flags & NON_DEFAULT_CONTEXT) {
602                 /* show context */
603                 offset += dissect_octet_string(tvb, subtree, offset, flags);
604         }
605
606         proto_tree_add_item(subtree, hf_reg_timeout, tvb, offset, 1, FALSE);
607         proto_tree_add_item(subtree, hf_reg_prio, tvb, offset+1, 1, FALSE);
608         proto_tree_add_item(subtree, hf_reg_rsid, tvb, offset+2, 1, FALSE);
609         offset+=4;
610
611         /* Region */
612
613         offset += dissect_object_id(tvb, subtree, offset, flags);
614
615         if(len > offset) {
616                 /* Upper bound (opt) */
617                 proto_tree_add_item(subtree, hf_reg_ubound, tvb, offset, 4, little_endian);
618                 offset += 4;
619         }
620 }
621
622
623 static void
624 dissect_unregister_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, char flags)
625 {
626         proto_item* item;
627         proto_tree* subtree;
628         gboolean little_endian = !(flags & NETWORK_BYTE_ORDER);
629
630         item = proto_tree_add_text(tree, tvb, offset, len, "Unregister-PDU");
631         subtree = proto_item_add_subtree(item, ett_unregister);
632
633         if(flags & NON_DEFAULT_CONTEXT) {
634                 /* show context */
635                 offset += dissect_octet_string(tvb, subtree, offset, flags);
636         }
637
638         proto_tree_add_item(subtree, hf_unreg_timeout, tvb, offset, 1, FALSE);
639         proto_tree_add_item(subtree, hf_unreg_prio, tvb, offset+1, 1, FALSE);
640         proto_tree_add_item(subtree, hf_unreg_rsid, tvb, offset+2, 1, FALSE);
641         offset+=4;
642
643         /* Region */
644         offset += dissect_object_id(tvb, subtree, offset, flags);
645
646         if(len > offset) {
647                 /* Upper bound (opt) */
648                 proto_tree_add_item(subtree, hf_unreg_ubound, tvb, offset, 4, little_endian);
649                 offset += 4;
650         }
651 }
652
653 static void
654 dissect_testset_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, char flags)
655 {
656         proto_item* item;
657         proto_tree* subtree;
658
659         item = proto_tree_add_text(tree, tvb, offset, len, "Testset-PDU");
660         subtree = proto_item_add_subtree(item, ett_testset);
661
662         if(flags & NON_DEFAULT_CONTEXT) {
663                 /* show context */
664                 offset += dissect_octet_string(tvb, subtree, offset, flags);
665         }
666
667         while(len > offset) {
668                 offset += dissect_varbind(tvb, subtree, offset, len, flags);
669         }
670 }
671
672 static void
673 dissect_notify_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, char flags)
674 {
675         proto_item* item;
676         proto_tree* subtree;
677
678         item = proto_tree_add_text(tree, tvb, offset, len, "Notify-PDU");
679         subtree = proto_item_add_subtree(item, ett_notify);
680
681         if(flags & NON_DEFAULT_CONTEXT) {
682                 /* show context */
683                 offset += dissect_octet_string(tvb, subtree, offset, flags);
684         }
685
686         while(len > offset) {
687                 offset += dissect_varbind(tvb, subtree, offset, len, flags);
688         }
689 }
690
691 static void
692 dissect_ping_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, char flags)
693 {
694         proto_item* item;
695         proto_tree* subtree;
696
697         item = proto_tree_add_text(tree, tvb, offset, len, "Ping-PDU");
698         subtree = proto_item_add_subtree(item, ett_ping);
699
700         if(flags & NON_DEFAULT_CONTEXT) {
701                 /* show context */
702                 offset += dissect_octet_string(tvb, subtree, offset, flags);
703         }
704 }
705
706 static void
707 dissect_idx_alloc_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, char flags)
708 {
709         proto_item* item;
710         proto_tree* subtree;
711
712         item = proto_tree_add_text(tree, tvb, offset, len, "IndexAllocate-PDU");
713         subtree = proto_item_add_subtree(item, ett_idxalloc);
714
715         if(flags & NON_DEFAULT_CONTEXT) {
716                 /* show context */
717                 offset += dissect_octet_string(tvb, subtree, offset, flags);
718         }
719
720         while(len > offset) {
721                 offset += dissect_varbind(tvb, subtree, offset, len, flags);
722         }
723 }
724
725
726 static void
727 dissect_idx_dealloc_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, char flags)
728 {
729         proto_item* item;
730         proto_tree* subtree;
731
732         item = proto_tree_add_text(tree, tvb, offset, len, "IndexDeallocate-PDU");
733         subtree = proto_item_add_subtree(item, ett_idxdalloc);
734
735         if(flags & NON_DEFAULT_CONTEXT) {
736                 /* show context */
737                 offset += dissect_octet_string(tvb, subtree, offset, flags);
738         }
739
740         while(len > offset) {
741                 offset += dissect_varbind(tvb, subtree, offset, len, flags);
742         }
743 }
744
745 static void
746 dissect_add_caps_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, char flags)
747 {
748         proto_item* item;
749         proto_tree* subtree;
750
751         item = proto_tree_add_text(tree, tvb, offset, len, "AddAgentCaps-PDU");
752         subtree = proto_item_add_subtree(item, ett_addcap);
753
754         if(flags & NON_DEFAULT_CONTEXT) {
755                 /* show context */
756                 offset += dissect_octet_string(tvb, subtree, offset, flags);
757         }
758
759         offset += dissect_object_id(tvb, subtree, offset, flags);
760
761         offset += dissect_octet_string(tvb, subtree, offset, flags);
762 }
763
764 static void
765 dissect_rem_caps_pdu(tvbuff_t *tvb, proto_tree *tree, int offset, int len, char flags)
766 {
767         proto_item* item;
768         proto_tree* subtree;
769
770         item = proto_tree_add_text(tree, tvb, offset, len, "RemoveAgentCaps-PDU");
771         subtree = proto_item_add_subtree(item, ett_remcap);
772
773         if(flags & NON_DEFAULT_CONTEXT) {
774                 /* show context */
775                 offset += dissect_octet_string(tvb, subtree, offset, flags);
776         }
777
778         offset += dissect_object_id(tvb, subtree, offset, flags);
779 }
780
781
782 static guint
783 get_agentx_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
784 {
785         guint8  flags;
786         guint32 plen;
787
788         /*
789          * Get the payload length.
790          */
791         flags = tvb_get_guint8(tvb, offset + 2);
792         NORLEL(flags, plen, tvb, offset + 16);
793
794         /*
795          * Arbitrarily limit it to 2^24, so we don't have to worry about
796          * overflow.
797          */
798         if (plen > 0xFFFFFF)
799                 plen = 0xFFFFFF;
800
801         /*
802          * That length doesn't include the header; add that in.
803          */
804         return plen + 20;
805 }
806
807 static void
808 dissect_agentx_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
809 {
810         int offset = 0;
811         proto_tree* agentx_tree, *pdu_hdr_tree, *flags_tree;
812         proto_item* pdu_item , *t_item;
813         guint8 version;
814         guint8 type;
815         guint8 flags;
816         guint32 session_id;
817         guint32 trans_id;
818         guint32 packet_id;
819         guint32 payload_len;
820
821         version = tvb_get_guint8(tvb, 0); offset+=1;
822         type = tvb_get_guint8(tvb, 1); offset+=1;
823         flags = tvb_get_guint8(tvb, 2); offset+=1;
824         /* skip reserved byte */
825         offset+=1;
826
827         NORLEL(flags, session_id, tvb, 4); offset+=4;
828         NORLEL(flags, trans_id, tvb, 8); offset+=4;
829         NORLEL(flags, packet_id, tvb, 12); offset+=4;
830         NORLEL(flags, payload_len, tvb, 16); offset+=4;
831
832         col_set_str(pinfo->cinfo, COL_PROTOCOL, "AgentX");
833
834         col_add_fstr(pinfo->cinfo, COL_INFO, "%s: sid=%d, tid=%d, packid=%d, plen=%d",
835                      val_to_str(type, type_values, "unknown"),
836                      session_id, trans_id, packet_id, payload_len);
837
838
839         if(!tree)
840                 return;
841
842         /*t_item = proto_tree_add_item(tree, proto_agentx, tvb, 0, -1, FALSE);*/
843         t_item = proto_tree_add_protocol_format(tree, proto_agentx, tvb, 0, -1,
844                         "Agent Extensibility (AgentX) Protocol: %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         agentx_tree = proto_item_add_subtree(t_item, ett_agentx);
848
849         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",
850                         (char)type, payload_len, session_id, trans_id, packet_id);
851
852         pdu_hdr_tree = proto_item_add_subtree(pdu_item, ett_pdu_hdr);
853
854         proto_tree_add_uint(pdu_hdr_tree, hf_version, tvb, 0, 1, version);
855         proto_tree_add_uint(pdu_hdr_tree, hf_type, tvb, 1, 1, type);
856
857         t_item = proto_tree_add_text(pdu_hdr_tree, tvb, 2, 1, "Flags: 0x%02x", flags);
858         flags_tree = proto_item_add_subtree(t_item, ett_flags);
859         proto_tree_add_boolean(flags_tree, hf_flags_register,   tvb, 2, 1, flags);
860         proto_tree_add_boolean(flags_tree, hf_flags_newindex,   tvb, 2, 1, flags);
861         proto_tree_add_boolean(flags_tree, hf_flags_anyindex,   tvb, 2, 1, flags);
862         proto_tree_add_boolean(flags_tree, hf_flags_context,    tvb, 2, 1, flags);
863         proto_tree_add_boolean(flags_tree, hf_flags_byteorder,  tvb, 2, 1, flags);
864
865         proto_tree_add_uint(pdu_hdr_tree, hf_session_id, tvb, 4, 4, session_id);
866         proto_tree_add_uint(pdu_hdr_tree, hf_trans_id, tvb, 8, 4, trans_id);
867         proto_tree_add_uint(pdu_hdr_tree, hf_packet_id, tvb, 12, 4, packet_id);
868         proto_tree_add_uint(pdu_hdr_tree, hf_payload_len, tvb, 16, 4, payload_len);
869
870         switch(type) {
871                 case AGENTX_OPEN_PDU:
872                 dissect_open_pdu(tvb, agentx_tree, offset, payload_len, flags);
873                 break;
874
875                 case AGENTX_CLOSE_PDU:
876                 dissect_close_pdu(tvb, agentx_tree, offset, payload_len);
877                 break;
878
879                 case AGENTX_REGISTER_PDU:
880                 dissect_register_pdu(tvb, agentx_tree, offset, payload_len, flags);
881                 break;
882
883                 case AGENTX_UNREGISTER_PDU:
884                 dissect_unregister_pdu(tvb, agentx_tree, offset, payload_len, flags);
885                 break;
886
887                 case AGENTX_GET_PDU:
888                 dissect_get_pdu(tvb, agentx_tree, offset, payload_len, flags);
889                 break;
890
891                 case AGENTX_GETNEXT_PDU:
892                 dissect_getnext_pdu(tvb, agentx_tree, offset, payload_len, flags);
893                 break;
894
895                 case AGENTX_GETBULK_PDU:
896                 dissect_getbulk_pdu(tvb, agentx_tree, offset, payload_len, flags);
897                 break;
898
899                 case AGENTX_TESTSET_PDU:
900                 dissect_testset_pdu(tvb, agentx_tree, offset, payload_len, flags);
901                 break;
902
903                 case AGENTX_COMMITSET_PDU:
904                 case AGENTX_UNDOSET_PDU:
905                 case AGENTX_CLEANUPSET_PDU:
906                         /* there is no parameters */
907                 break;
908
909                 case AGENTX_NOTIFY_PDU:
910                 dissect_notify_pdu(tvb, agentx_tree, offset, payload_len, flags);
911                 break;
912
913                 case AGENTX_PING_PDU:
914                 dissect_ping_pdu(tvb, agentx_tree, offset, payload_len, flags);
915                 break;
916
917                 case AGENTX_INDEX_ALLOC_PDU:
918                 dissect_idx_alloc_pdu(tvb, agentx_tree, offset, payload_len, flags);
919                 break;
920
921                 case AGENTX_INDEX_DEALLOC_PDU:
922                 dissect_idx_dealloc_pdu(tvb, agentx_tree, offset, payload_len, flags);
923                 break;
924
925                 case AGENTX_ADD_AGENT_CAPS_PDU:
926                 dissect_add_caps_pdu(tvb, agentx_tree, offset, payload_len, flags);
927                 break;
928
929                 case AGENTX_REM_AGENT_CAPS_PDU:
930                 dissect_rem_caps_pdu(tvb, agentx_tree, offset, payload_len, flags);
931                 break;
932
933                 case AGENTX_RESPONSE_PDU:
934                 dissect_response_pdu(tvb, agentx_tree, offset, payload_len, flags);
935                 break;
936         }
937 }
938
939 static void
940 dissect_agentx(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
941 {
942         tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 20, get_agentx_pdu_len,
943                          dissect_agentx_pdu);
944 }
945
946 static const true_false_string tfs_agentx_register      = { "Yes",                      "No"    };
947 static const true_false_string tfs_agentx_newindex      = { "Yes",                      "No"    };
948 static const true_false_string tfs_agentx_anyindex      = { "Yes",                      "No"    };
949 static const true_false_string tfs_agentx_context       = { "Provided",                 "None"  };
950 static const true_false_string tfs_agentx_byteorder     = { "MSB (network order)",      "LSB"   };
951
952 void
953 proto_register_agentx(void)
954 {
955         static hf_register_info hf[] = {
956
957                 { &hf_version,
958                   { "Version", "agentx.version", FT_UINT8, BASE_DEC, NULL, 0x0,
959                     "header version", HFILL }},
960
961                 { &hf_type,
962                   { "Type", "agentx.type", FT_UINT8, BASE_DEC, VALS(type_values), 0x0,
963                     "header type", HFILL }},
964
965                 { &hf_flags,
966                   { "Flags", "agentx.flags", FT_UINT8, BASE_DEC, NULL, 0x0,
967                     "header type", HFILL }},
968
969                 { &hf_flags_register,
970                   { "Register", "agentx.flags.register", FT_BOOLEAN, 8, TFS(&tfs_agentx_register),
971                     INSTANCE_REGISTRATION, "Instance Registration",  HFILL }},
972
973                 { &hf_flags_newindex,
974                   { "New Index", "agentx.flags.newindex", FT_BOOLEAN, 8, TFS(&tfs_agentx_newindex),
975                     NEW_INDEX, "New Index Requested",  HFILL }},
976
977                 { &hf_flags_anyindex,
978                   { "Any Index", "agentx.flags.anyindex", FT_BOOLEAN, 8, TFS(&tfs_agentx_anyindex),
979                     ANY_INDEX, "Any Index Requested",  HFILL }},
980
981                 { &hf_flags_context,
982                   { "Non-default Context", "agentx.flags.context", FT_BOOLEAN, 8, TFS(&tfs_agentx_context),
983                     NON_DEFAULT_CONTEXT, NULL,  HFILL }},
984
985                 { &hf_flags_byteorder,
986                   { "Byte Order", "agentx.flags.byteorder", FT_BOOLEAN, 8, TFS(&tfs_agentx_byteorder),
987                     NETWORK_BYTE_ORDER, NULL,  HFILL }},
988
989                 { &hf_session_id,
990                   { "sessionID", "agentx.session_id", FT_UINT32, BASE_DEC, NULL, 0x0,
991                     "Session ID", HFILL }},
992
993                 { &hf_trans_id,
994                   { "TransactionID", "agentx.transaction_id", FT_UINT32, BASE_DEC, NULL, 0x0,
995                     "Transaction ID", HFILL }},
996
997                 { &hf_packet_id,
998                   { "PacketID", "agentx.packet_id", FT_UINT32, BASE_DEC, NULL, 0x0,
999                     "Packet ID", HFILL }},
1000
1001                 { &hf_payload_len,
1002                   { "Payload length", "agentx.payload_len", FT_UINT32, BASE_DEC, NULL, 0x0,
1003                     NULL, HFILL }},
1004
1005                 { &hf_ostring,
1006                   { "Octet String", "agentx.ostring", FT_STRING, BASE_NONE, NULL, 0x0,
1007                     NULL, HFILL }},
1008
1009                 { &hf_ostring_len,
1010                   { "OString len", "agentx.ostring_len", FT_UINT32, BASE_DEC, NULL, 0x0,
1011                     "Octet String Length", HFILL }},
1012
1013                 { &hf_oid_sub,
1014                   { "Number subids", "agentx.n_subid", FT_UINT8, BASE_DEC, NULL, 0x0,
1015                     NULL, HFILL }},
1016
1017                 { &hf_oid_prefix,
1018                   { "OID prefix", "agentx.oid_prefix", FT_UINT8, BASE_DEC, NULL, 0x0,
1019                     NULL, HFILL }},
1020
1021                 { &hf_oid_include,
1022                   { "OID include", "agentx.oid_include", FT_UINT8, BASE_DEC, NULL, 0x0,
1023                     NULL, HFILL }},
1024
1025                 { &hf_oid_str,
1026                   { "OID", "agentx.oid", FT_STRING, BASE_NONE, NULL, 0x0,
1027                     NULL, HFILL }},
1028
1029                 { &hf_resp_uptime,
1030                   { "sysUpTime", "agentx.r.uptime", FT_UINT32, BASE_DEC, NULL, 0x0,
1031                     NULL, HFILL }},
1032
1033                 { &hf_resp_error,
1034                   { "Resp. error", "agentx.r.error", FT_UINT16, BASE_DEC, VALS(resp_errors), 0x0,
1035                     "response error", HFILL }},
1036
1037                 { &hf_resp_index,
1038                   { "Resp. index", "agentx.r.index", FT_UINT16, BASE_DEC, NULL, 0x0,
1039                     "response index", HFILL }},
1040
1041                 { &hf_vtag,
1042                   { "Variable type", "agentx.v.tag", FT_UINT16, BASE_DEC, VALS(vtag_values), 0x0,
1043                     "vtag", HFILL }},
1044
1045                 { &hf_val32,
1046                   { "Value(32)", "agentx.v.val32", FT_UINT32, BASE_DEC, NULL, 0x0,
1047                     "val32", HFILL }},
1048
1049                 { &hf_val64,
1050                   { "Value(64)", "agentx.v.val64", FT_UINT64, BASE_DEC, NULL, 0x0,
1051                     "val64", HFILL }},
1052
1053                 { &hf_open_timeout,
1054                   { "Timeout", "agentx.o.timeout", FT_UINT8, BASE_DEC, NULL, 0x0,
1055                     "open timeout", HFILL }},
1056
1057                 { &hf_close_reason,
1058                   { "Reason", "agentx.c.reason", FT_UINT8, BASE_DEC, VALS(close_reasons), 0x0,
1059                     "close reason", HFILL }},
1060
1061                 { &hf_reg_timeout,
1062                   { "Timeout", "agentx.r.timeout", FT_UINT8, BASE_DEC, NULL, 0x0,
1063                     "Register timeout", HFILL }},
1064
1065                 { &hf_reg_prio,
1066                   { "Priority", "agentx.r.priority", FT_UINT8, BASE_DEC, NULL, 0x0,
1067                     "Register Priority", HFILL }},
1068
1069                 { &hf_reg_rsid,
1070                   { "Range_subid", "agentx.r.range_subid", FT_UINT8, BASE_DEC, NULL, 0x0,
1071                     "Register range_subid", HFILL }},
1072
1073                 { &hf_reg_ubound,
1074                   { "Upper bound", "agentx.r.upper_bound", FT_UINT32, BASE_DEC, NULL, 0x0,
1075                     "Register upper bound", HFILL }},
1076
1077                 { &hf_unreg_timeout,
1078                   { "Timeout", "agentx.u.timeout", FT_UINT8, BASE_DEC, NULL, 0x0,
1079                     "Unregister timeout", HFILL }},
1080
1081                 { &hf_unreg_prio,
1082                   { "Priority", "agentx.u.priority", FT_UINT8, BASE_DEC, NULL, 0x0,
1083                     "Unregister Priority", HFILL }},
1084
1085                 { &hf_unreg_rsid,
1086                   { "Range_subid", "agentx.u.range_subid", FT_UINT8, BASE_DEC, NULL, 0x0,
1087                     "Unregister range_subid", HFILL }},
1088
1089                 { &hf_unreg_ubound,
1090                   { "Upper bound", "agentx.u.upper_bound", FT_UINT32, BASE_DEC, NULL, 0x0,
1091                     "Register upper bound", HFILL }},
1092
1093                 { &hf_gbulk_nrepeat,
1094                   { "Repeaters", "agentx.gb.nrepeat", FT_UINT16, BASE_DEC, NULL, 0x0,
1095                     "getBulk Num. repeaters", HFILL }},
1096
1097                 { &hf_gbulk_mrepeat,
1098                   { "Max Repetition", "agentx.gb.mrepeat", FT_UINT16, BASE_DEC, NULL, 0x0,
1099                     "getBulk Max repetition", HFILL }},
1100
1101
1102                 /* Add more fields here */
1103
1104         };
1105
1106         static gint *ett[] = {
1107                 &ett_agentx,
1108                 &ett_pdu_hdr,
1109                 &ett_get,
1110                 &ett_getnext,
1111                 &ett_search_range,
1112                 &ett_obj_ident,
1113                 &ett_response,
1114                 &ett_valrep,
1115                 &ett_open,
1116                 &ett_close,
1117                 &ett_register,
1118                 &ett_unregister,
1119                 &ett_getbulk,
1120                 &ett_testset,
1121                 &ett_commitset,
1122                 &ett_undoset,
1123                 &ett_cleanupset,
1124                 &ett_notify,
1125                 &ett_ping,
1126                 &ett_idxalloc,
1127                 &ett_idxdalloc,
1128                 &ett_addcap,
1129                 &ett_remcap,
1130                 &ett_flags,
1131         };
1132
1133
1134         module_t *agentx_module;
1135
1136         proto_agentx = proto_register_protocol("AgentX",
1137                                                "AgentX", "agentx");
1138
1139         proto_register_field_array(proto_agentx, hf, array_length(hf));
1140         proto_register_subtree_array(ett, array_length(ett));
1141
1142         agentx_module = prefs_register_protocol(proto_agentx, proto_reg_handoff_agentx);
1143
1144         prefs_register_uint_preference(agentx_module, "tcp.agentx_port",
1145                                        "AgentX listener TCP Port",
1146                                        "Set the TCP port for AgentX"
1147                                        "(if other than the default of 705)",
1148                                        10, &global_agentx_tcp_port);
1149 }
1150
1151 /* The registration hand-off routine */
1152 void
1153 proto_reg_handoff_agentx(void)
1154 {
1155         static gboolean agentx_prefs_initialized = FALSE;
1156         static dissector_handle_t agentx_handle;
1157         static guint agentx_tcp_port;
1158
1159         if(!agentx_prefs_initialized) {
1160                 agentx_handle = create_dissector_handle(dissect_agentx, proto_agentx);
1161                 agentx_prefs_initialized = TRUE;
1162         }
1163         else {
1164                 dissector_delete_uint("tcp.port", agentx_tcp_port, agentx_handle);
1165         }
1166
1167         agentx_tcp_port = global_agentx_tcp_port;
1168         dissector_add_uint("tcp.port", agentx_tcp_port, agentx_handle);
1169 }