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