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