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