In packet-cops.c use proto_item_append_text() instead of creating a
[metze/wireshark/wip.git] / asn1 / snmp / packet-snmp-template.c
1 /* packet-snmp.c
2  * Routines for SNMP (simple network management protocol)
3  * Copyright (C) 1998 Didier Jorand
4  *
5  * See RFC 1157 for SNMPv1.
6  *
7  * See RFCs 1901, 1905, and 1906 for SNMPv2c.
8  *
9  * See RFCs 1905, 1906, 1909, and 1910 for SNMPv2u [historic].
10  *
11  * See RFCs 2570-2576 for SNMPv3
12  * Updated to use the asn2eth compiler made by Tomas Kukosa
13  * Copyright (C) 2005 Anders Broman [AT] ericsson.com
14  *
15  *
16  * $Id$
17  *
18  * Ethereal - Network traffic analyzer
19  * By Gerald Combs <gerald@ethereal.com>
20  * Copyright 1998 Gerald Combs
21  *
22  * Some stuff from:
23  *
24  * GXSNMP -- An snmp mangament application
25  * Copyright (C) 1998 Gregory McLean & Jochen Friedrich
26  * Beholder RMON ethernet network monitor,Copyright (C) 1993 DNPAP group
27  *
28  * This program is free software; you can redistribute it and/or
29  * modify it under the terms of the GNU General Public License
30  * as published by the Free Software Foundation; either version 2
31  * of the License, or (at your option) any later version.
32  *
33  * This program is distributed in the hope that it will be useful,
34  * but WITHOUT ANY WARRANTY; without even the implied warranty of
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36  * GNU General Public License for more details.
37  *
38  * You should have received a copy of the GNU General Public License
39  * along with this program; if not, write to the Free Software
40  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
41  */
42
43 #ifdef HAVE_CONFIG_H
44 # include "config.h"
45 #endif
46
47 #include <stdio.h>
48 #include <string.h>
49
50 #include <glib.h>
51
52 #include <epan/packet.h>
53 #include <epan/conversation.h>
54 #include "etypes.h"
55 #include <epan/prefs.h>
56 #include <epan/sminmpec.h>
57 #include <epan/emem.h>
58 #include "packet-ipx.h"
59 #include "packet-hpext.h"
60
61
62 #include "packet-ber.h"
63
64 #ifdef HAVE_SOME_SNMP
65
66 #ifdef HAVE_NET_SNMP
67 # include <net-snmp/net-snmp-config.h>
68 # include <net-snmp/mib_api.h>
69 # include <net-snmp/library/default_store.h>
70 # include <net-snmp/config_api.h>
71 #else /* HAVE_NET_SNMP */
72 # include <ucd-snmp/ucd-snmp-config.h>
73 # include <ucd-snmp/asn1.h>
74 # include <ucd-snmp/snmp_api.h>
75 # include <ucd-snmp/snmp_impl.h>
76 # include <ucd-snmp/mib.h>
77 # include <ucd-snmp/default_store.h>
78 # include <ucd-snmp/read_config.h>
79 # include <ucd-snmp/tools.h>
80 #endif /* HAVE_NET_SNMP */
81
82 #ifndef NETSNMP_DS_LIBRARY_ID
83 # define NETSNMP_DS_LIBRARY_ID DS_LIBRARY_ID
84 # define NETSNMP_DS_LIB_NO_TOKEN_WARNINGS DS_LIB_NO_TOKEN_WARNINGS
85 # define NETSNMP_DS_LIB_PRINT_SUFFIX_ONLY DS_LIB_PRINT_SUFFIX_ONLY
86 # define netsnmp_ds_set_boolean ds_set_boolean
87 # define netsnmp_ds_set_int ds_set_int
88 #endif
89
90 #ifdef _WIN32
91 # include <epan/filesystem.h>
92 #endif /* _WIN32 */
93
94    /*
95     * Define values "sprint_realloc_value()" expects.
96     */
97 # define VALTYPE_INTEGER        ASN_INTEGER
98 # define VALTYPE_COUNTER        ASN_COUNTER
99 # define VALTYPE_GAUGE          ASN_GAUGE
100 # define VALTYPE_TIMETICKS      ASN_TIMETICKS
101 # define VALTYPE_STRING         ASN_OCTET_STR
102 # define VALTYPE_IPADDR         ASN_IPADDRESS
103 # define VALTYPE_OPAQUE         ASN_OPAQUE
104 # define VALTYPE_NSAP           ASN_NSAP
105 # define VALTYPE_OBJECTID       ASN_OBJECT_ID
106 # define VALTYPE_BITSTR         ASN_BIT_STR
107 # define VALTYPE_COUNTER64      ASN_COUNTER64
108
109 #endif /* HAVE_SOME_SNMP */
110
111 #include "packet-snmp.h"
112 #include "format-oid.h"
113
114 #define PNAME  "Simple Network Management Protocol"
115 #define PSNAME "SNMP"
116 #define PFNAME "snmp"
117
118 #define UDP_PORT_SNMP           161
119 #define UDP_PORT_SNMP_TRAP      162
120 #define TCP_PORT_SNMP           161
121 #define TCP_PORT_SNMP_TRAP      162
122 #define TCP_PORT_SMUX           199
123
124 /* Initialize the protocol and registered fields */
125 static int proto_snmp = -1;
126 static int proto_smux = -1;
127
128 /* Default MIB modules to load */
129 /*
130  * XXX - According to Wes Hardaker, we shouldn't do this:
131  *       http://www.ethereal.com/lists/ethereal-dev/200412/msg00222.html
132  */
133 #ifdef _WIN32
134 # define DEF_MIB_MODULES "IP-MIB;IF-MIB;TCP-MIB;UDP-MIB;SNMPv2-MIB;RFC1213-MIB;UCD-SNMP-MIB"
135 # define IMPORT_SEPARATOR ":"
136 #else
137 # define DEF_MIB_MODULES "IP-MIB:IF-MIB:TCP-MIB:UDP-MIB:SNMPv2-MIB:RFC1213-MIB:UCD-SNMP-MIB"
138 # define IMPORT_SEPARATOR ";"
139 #endif /* _WIN32 */
140
141 static const gchar *mib_modules = DEF_MIB_MODULES;
142 static gboolean display_oid = TRUE;
143
144 /* Subdissector tables */
145 static dissector_table_t variable_oid_dissector_table;
146
147 #define TH_AUTH   0x01
148 #define TH_CRYPT  0x02
149 #define TH_REPORT 0x04
150
151 /* desegmentation of SNMP-over-TCP */
152 static gboolean snmp_desegment = TRUE;
153
154 /* Global variables */
155
156 guint32 MsgSecurityModel;
157
158 static dissector_handle_t snmp_handle;
159 static dissector_handle_t data_handle;
160
161 static int hf_snmp_v3_flags_auth = -1;
162 static int hf_snmp_v3_flags_crypt = -1;
163 static int hf_snmp_v3_flags_report = -1;
164
165 static int hf_snmp_engineid_conform = -1;
166 static int hf_snmp_engineid_enterprise = -1;
167 static int hf_snmp_engineid_format = -1;
168 static int hf_snmp_engineid_ipv4 = -1;
169 static int hf_snmp_engineid_ipv6 = -1;
170 static int hf_snmp_engineid_mac = -1;
171 static int hf_snmp_engineid_text = -1;
172 static int hf_snmp_engineid_time = -1;
173 static int hf_snmp_engineid_data = -1;
174 #include "packet-snmp-hf.c"
175
176 static int hf_smux_version = -1;
177 static int hf_smux_pdutype = -1;
178
179 /* Initialize the subtree pointers */
180 static gint ett_smux = -1;
181 static gint ett_snmp = -1;
182 static gint ett_engineid = -1;
183 static gint ett_msgFlags = -1;
184
185 #include "packet-snmp-ett.c"
186
187
188 /* Security Models */
189
190 #define SNMP_SEC_ANY                    0
191 #define SNMP_SEC_V1                             1
192 #define SNMP_SEC_V2C                    2
193 #define SNMP_SEC_USM                    3
194
195 static const value_string sec_models[] = {
196         { SNMP_SEC_ANY,                 "Any" },
197         { SNMP_SEC_V1,                  "V1" },
198         { SNMP_SEC_V2C,                 "V2C" },
199         { SNMP_SEC_USM,                 "USM" },
200         { 0,                            NULL }
201 };
202
203 /* SMUX PDU types */
204 #define SMUX_MSG_OPEN           0
205 #define SMUX_MSG_CLOSE          1
206 #define SMUX_MSG_RREQ           2
207 #define SMUX_MSG_RRSP           3
208 #define SMUX_MSG_SOUT           4
209
210 static const value_string smux_types[] = {
211         { SMUX_MSG_OPEN,        "Open" },
212         { SMUX_MSG_CLOSE,       "Close" },
213         { SMUX_MSG_RREQ,        "Registration Request" },
214         { SMUX_MSG_RRSP,        "Registration Response" },
215         { SMUX_MSG_SOUT,        "Commit Or Rollback" },
216         { 0,                    NULL }
217 };
218
219 int oid_to_subid_buf(const guint8 *oid, gint oid_len, subid_t *buf, int buf_len) {
220    int i, out_len;
221    guint8 byte;
222    guint32 value;
223
224    value=0; out_len = 0;
225    for (i=0; i<oid_len; i++){
226      if (out_len >= buf_len) break;
227      byte = oid[i];
228      if (i == 0) {
229        buf[out_len++] = byte/40;
230        buf[out_len++] = byte%40;
231        continue;
232      }
233      value = (value << 7) | (byte & 0x7F);
234      if (byte & 0x80) {
235        continue;
236      }
237      buf[out_len++] = value;
238      value = 0;
239    }
240
241    return out_len;
242 }
243
244 gchar *
245 format_oid(subid_t *oid, guint oid_length)
246 {
247         char *result;
248         int result_len;
249         int len;
250         unsigned int i;
251         char *buf;
252 #ifdef HAVE_SOME_SNMP
253         guchar *oid_string;
254         size_t oid_string_len;
255         size_t oid_out_len;
256 #endif
257
258         result_len = oid_length * 22;
259
260 #ifdef HAVE_SOME_SNMP
261         /*
262          * Get the decoded form of the OID, and add its length to the
263          * length of the result string.
264          *
265          * XXX - check for "sprint_realloc_objid()" failure.
266          * XXX - if we convert this to ep_alloc(), make sure the fourth
267          * argument to sprint_realloc_objid() is FALSE.
268          */
269         oid_string_len = 256;
270         oid_string = malloc(oid_string_len);
271         if (oid_string == NULL)
272                 return NULL;
273         *oid_string = '\0';
274         oid_out_len = 0;
275         sprint_realloc_objid(&oid_string, &oid_string_len, &oid_out_len, TRUE,
276             oid, oid_length);
277         result_len += strlen(oid_string) + 3;
278 #endif
279
280         result = ep_alloc(result_len + 1);
281         buf = result;
282         len = g_snprintf(buf, result_len + 1 - (buf-result), "%lu", (unsigned long)oid[0]);
283         buf += len;
284         for (i = 1; i < oid_length;i++) {
285                 len = g_snprintf(buf, result_len + 1 - (buf-result), ".%lu", (unsigned long)oid[i]);
286                 buf += len;
287         }
288
289 #ifdef HAVE_SOME_SNMP
290         /*
291          * Append the decoded form of the OID.
292          */
293         g_snprintf(buf, result_len + 1 -(buf-result), " (%s)", oid_string);
294         free(oid_string);
295 #endif
296
297         return result;
298 }
299
300 /* returns the decoded (can be NULL) and non_decoded OID strings,
301    returned pointers shall be freed by the caller */
302 void
303 new_format_oid(subid_t *oid, guint oid_length,
304                gchar **non_decoded, gchar **decoded)
305 {
306         int non_decoded_len;
307         int len;
308         unsigned int i;
309         char *buf;
310
311 #ifdef HAVE_SOME_SNMP
312         guchar *oid_string;
313         size_t oid_string_len;
314         size_t oid_out_len;
315
316         /*
317          * Get the decoded form of the OID, and add its length to the
318          * length of the result string.
319          */
320
321         /*
322          * XXX - if we convert this to ep_alloc(), make sure the fourth
323          * argument to sprint_realloc_objid() is FALSE.
324          */
325
326         oid_string_len = 256;
327         oid_string = malloc(oid_string_len);
328         if (oid_string != NULL) {
329                 *oid_string = '\0';
330                 oid_out_len = 0;
331                 sprint_realloc_objid(&oid_string, &oid_string_len, &oid_out_len, TRUE,
332                                      oid, oid_length);
333         }
334         *decoded = oid_string;
335 #else
336         *decoded = NULL;
337 #endif
338
339         non_decoded_len = oid_length * 22 + 1;
340         *non_decoded = ep_alloc(non_decoded_len);
341         buf = *non_decoded;
342         len = g_snprintf(buf, non_decoded_len-(buf-*non_decoded), "%lu", (unsigned long)oid[0]);
343         buf += len;
344         for (i = 1; i < oid_length; i++) {
345           len = g_snprintf(buf, non_decoded_len-(buf-*non_decoded), ".%lu", (unsigned long)oid[i]);
346           buf += len;
347         }
348 }
349
350
351 #define F_SNMP_ENGINEID_CONFORM 0x80
352 #define SNMP_ENGINEID_RFC1910 0x00
353 #define SNMP_ENGINEID_RFC3411 0x01
354
355 static const true_false_string tfs_snmp_engineid_conform = {
356   "RFC3411 (SNMPv3)",
357   "RFC1910 (Non-SNMPv3)"
358 };
359
360 #define SNMP_ENGINEID_FORMAT_IPV4 0x01
361 #define SNMP_ENGINEID_FORMAT_IPV6 0x02
362 #define SNMP_ENGINEID_FORMAT_MACADDRESS 0x03
363 #define SNMP_ENGINEID_FORMAT_TEXT 0x04
364 #define SNMP_ENGINEID_FORMAT_OCTETS 0x05
365
366 static const value_string snmp_engineid_format_vals[] = {
367         { SNMP_ENGINEID_FORMAT_IPV4,    "IPv4 address" },
368         { SNMP_ENGINEID_FORMAT_IPV6,    "IPv6 address" },
369         { SNMP_ENGINEID_FORMAT_MACADDRESS,      "MAC address" },
370         { SNMP_ENGINEID_FORMAT_TEXT,    "Text, administratively assigned" },
371         { SNMP_ENGINEID_FORMAT_OCTETS,  "Octets, administratively assigned" },
372         { 0,    NULL }
373 };
374
375 /*
376  * SNMP Engine ID dissection according to RFC 3411 (SnmpEngineID TC)
377  * or historic RFC 1910 (AgentID)
378  */
379 int
380 dissect_snmp_engineid(proto_tree *tree, tvbuff_t *tvb, int offset, int len)
381 {
382     proto_item *item = NULL;
383     guint8 conformance, format;
384     guint32 enterpriseid, seconds;
385     nstime_t ts;
386     int len_remain = len;
387
388     /* first bit: engine id conformance */
389     if (len_remain<4) return offset;
390     conformance = ((tvb_get_guint8(tvb, offset)>>7) && 0x01);
391     proto_tree_add_item(tree, hf_snmp_engineid_conform, tvb, offset, 1, FALSE);
392
393     /* 4-byte enterprise number/name */
394     if (len_remain<4) return offset;
395     enterpriseid = tvb_get_ntohl(tvb, offset);
396     if (conformance)
397       enterpriseid -= 0x80000000; /* ignore first bit */
398     proto_tree_add_uint(tree, hf_snmp_engineid_enterprise, tvb, offset, 4, enterpriseid);
399     offset+=4;
400     len_remain-=4;
401
402     switch(conformance) {
403
404     case SNMP_ENGINEID_RFC1910:
405       /* 12-byte AgentID w/ 8-byte trailer */
406       if (len_remain==8) {
407         proto_tree_add_text(tree, tvb, offset, 8, "AgentID Trailer: 0x%s",
408                             tvb_bytes_to_str(tvb, offset, 8));
409         offset+=8;
410         len_remain-=8;
411       } else {
412         proto_tree_add_text(tree, tvb, offset, len_remain, "<Data not conforming to RFC1910>");
413         return offset;
414       }
415       break;
416
417     case SNMP_ENGINEID_RFC3411: /* variable length: 5..32 */
418
419       /* 1-byte format specifier */
420       if (len_remain<1) return offset;
421       format = tvb_get_guint8(tvb, offset);
422       item = proto_tree_add_uint_format(tree, hf_snmp_engineid_format, tvb, offset, 1, format, "Engine ID Format: %s (%d)",
423                           val_to_str(format, snmp_engineid_format_vals, "Reserved/Enterprise-specific"), format);
424       offset+=1;
425       len_remain-=1;
426
427       switch(format) {
428       case SNMP_ENGINEID_FORMAT_IPV4:
429         /* 4-byte IPv4 address */
430         if (len_remain==4) {
431           proto_tree_add_item(tree, hf_snmp_engineid_ipv4, tvb, offset, 4, FALSE);
432           offset+=4;
433           len_remain=0;
434         }
435         break;
436       case SNMP_ENGINEID_FORMAT_IPV6:
437         /* 16-byte IPv6 address */
438         if (len_remain==16) {
439           proto_tree_add_item(tree, hf_snmp_engineid_ipv6, tvb, offset, 16, FALSE);
440           offset+=16;
441           len_remain=0;
442         }
443         break;
444       case SNMP_ENGINEID_FORMAT_MACADDRESS:
445         /* 6-byte MAC address */
446         if (len_remain==6) {
447           proto_tree_add_item(tree, hf_snmp_engineid_mac, tvb, offset, 6, FALSE);
448           offset+=6;
449           len_remain=0;
450         }
451         break;
452       case SNMP_ENGINEID_FORMAT_TEXT:
453         /* max. 27-byte string, administratively assigned */
454         if (len_remain<=27) {
455           proto_tree_add_item(tree, hf_snmp_engineid_text, tvb, offset, len_remain, FALSE);
456           offset+=len_remain;
457           len_remain=0;
458         }
459         break;
460       case 128:
461         /* most common enterprise-specific format: (ucd|net)-snmp random */
462         if ((enterpriseid==2021)||(enterpriseid==8072)) {
463           proto_item_append_text(item, (enterpriseid==2021) ? ": UCD-SNMP Random" : ": Net-SNMP Random");
464           /* demystify: 4B random, 4B epoch seconds */
465           if (len_remain==8) {
466             proto_tree_add_item(tree, hf_snmp_engineid_data, tvb, offset, 4, FALSE);
467             seconds = tvb_get_letohl(tvb, offset+4);
468             ts.secs = seconds;
469             proto_tree_add_time_format(tree, hf_snmp_engineid_time, tvb, offset+4, 4,
470                                   &ts, "Engine ID Data: Creation Time: %s",
471                                   abs_time_secs_to_str(seconds));
472             offset+=8;
473             len_remain=0;
474           }
475         }
476         break;
477       case SNMP_ENGINEID_FORMAT_OCTETS:
478       default:
479         /* max. 27 bytes, administratively assigned or unknown format */
480         if (len_remain<=27) {
481           proto_tree_add_item(tree, hf_snmp_engineid_data, tvb, offset, len_remain, FALSE);
482           offset+=len_remain;
483           len_remain=0;
484         }
485         break;
486       }
487     }
488
489     if (len_remain>0) {
490       proto_tree_add_text(tree, tvb, offset, len_remain, "<Data not conforming to RFC3411>");
491       offset+=len_remain;
492     }
493     return offset;
494 }
495
496 #include "packet-snmp-fn.c"
497
498 guint
499 dissect_snmp_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
500     proto_tree *tree, int proto, gint ett, gboolean is_tcp)
501 {
502
503         guint length_remaining;
504         gint8 class;
505         gboolean pc, ind = 0;
506         gint32 tag;
507         guint32 len;
508         guint message_length;
509         int start_offset = offset;
510         guint32 version = 0;
511
512         proto_tree *snmp_tree = NULL;
513         proto_item *item = NULL;
514
515         /*
516          * This will throw an exception if we don't have any data left.
517          * That's what we want.  (See "tcp_dissect_pdus()", which is
518          * similar, but doesn't have to deal with ASN.1.
519          * XXX - can we make "tcp_dissect_pdus()" provide enough
520          * information to the "get_pdu_len" routine so that we could
521          * have that routine deal with ASN.1, and just use
522          * "tcp_dissect_pdus()"?)
523          */
524         length_remaining = tvb_ensure_length_remaining(tvb, offset);
525
526         /* NOTE: we have to parse the message piece by piece, since the
527          * capture length may be less than the message length: a 'global'
528          * parsing is likely to fail.
529          */
530
531         /*
532          * If this is SNMP-over-TCP, we might have to do reassembly
533          * in order to read the "Sequence Of" header.
534          */
535         if (is_tcp && snmp_desegment && pinfo->can_desegment) {
536                 /*
537                  * This is TCP, and we should, and can, do reassembly.
538                  *
539                  * Is the "Sequence Of" header split across segment
540                  * boundaries?  We requre at least 6 bytes for the
541                  * header, which allows for a 4-byte length (ASN.1
542                  * BER).
543                  */
544                 if (length_remaining < 6) {
545                         pinfo->desegment_offset = offset;
546                         pinfo->desegment_len = 6 - length_remaining;
547
548                         /*
549                          * Return 0, which means "I didn't dissect anything
550                          * because I don't have enough data - we need
551                          * to desegment".
552                          */
553                         return 0;
554                 }
555         }
556
557         /*
558          * OK, try to read the "Sequence Of" header; this gets the total
559          * length of the SNMP message.
560          */
561         /* Set tree to 0 to not display internakl BER fields if option used.*/
562         offset = dissect_ber_identifier(pinfo, 0, tvb, offset, &class, &pc, &tag);
563         offset = dissect_ber_length(pinfo, 0, tvb, offset, &len, &ind);
564
565         message_length = len + 2;
566         offset = dissect_ber_integer(FALSE, pinfo, 0, tvb, offset, -1, &version);
567
568
569         /*
570          * If this is SNMP-over-TCP, we might have to do reassembly
571          * to get all of this message.
572          */
573         if (is_tcp && snmp_desegment && pinfo->can_desegment) {
574                 /*
575                  * Yes - is the message split across segment boundaries?
576                  */
577                 if (length_remaining < message_length) {
578                         /*
579                          * Yes.  Tell the TCP dissector where the data
580                          * for this message starts in the data it handed
581                          * us, and how many more bytes we need, and
582                          * return.
583                          */
584                         pinfo->desegment_offset = start_offset;
585                         pinfo->desegment_len =
586                             message_length - length_remaining;
587
588                         /*
589                          * Return 0, which means "I didn't dissect anything
590                          * because I don't have enough data - we need
591                          * to desegment".
592                          */
593                         return 0;
594                 }
595         }
596
597         if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
598                 col_set_str(pinfo->cinfo, COL_PROTOCOL,
599                     proto_get_protocol_short_name(find_protocol_by_id(proto)));
600         }
601
602         if (tree) {
603                 item = proto_tree_add_item(tree, proto, tvb, offset,
604                     message_length, FALSE);
605                 snmp_tree = proto_item_add_subtree(item, ett);
606         }
607
608         switch (version){
609         case 0: /* v1 */
610         case 1: /* v2c */
611                 offset = dissect_snmp_Message(FALSE , tvb, start_offset, pinfo, snmp_tree, -1);
612                 break;
613         case 2: /* v2u */
614                 offset = dissect_snmp_Messagev2u(FALSE , tvb, start_offset, pinfo, snmp_tree, -1);
615                 break;
616                         /* v3 */
617         case 3:
618                 offset = dissect_snmp_SNMPv3Message(FALSE , tvb, start_offset, pinfo, snmp_tree, -1);
619                 break;
620         default:
621                 /*
622                  * Return the length remaining in the tvbuff, so
623                  * if this is SNMP-over-TCP, our caller thinks there's
624                  * nothing left to dissect.
625                  */
626                 proto_tree_add_text(snmp_tree, tvb, offset, -1,"Unknown version");
627                 return length_remaining;
628                 break;
629         }
630         return offset;
631
632
633
634 }
635
636 static gint
637 dissect_snmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
638 {
639         conversation_t  *conversation;
640         int offset;
641         gint8 tmp_class;
642         gboolean tmp_pc;
643         gint32 tmp_tag;
644         guint32 tmp_length;
645         gboolean tmp_ind;
646
647         /*
648          * See if this looks like SNMP or not. if not, return 0 so
649          * ethereal can try som other dissector instead.
650          */
651         /* All SNMP packets are BER encoded and consist of a SEQUENCE
652          * that spans the entire PDU. The first item is an INTEGER that
653          * has the values 0-2 (version 1-3).
654          * if not it is not snmp.
655          */
656         /* SNMP starts with a SEQUENCE */
657         offset = get_ber_identifier(tvb, 0, &tmp_class, &tmp_pc, &tmp_tag);
658         if((tmp_class!=BER_CLASS_UNI)||(tmp_tag!=BER_UNI_TAG_SEQUENCE)){
659                 return 0;
660         }
661         /* then comes a length which spans the rest of the tvb */
662         offset = get_ber_length(NULL, tvb, offset, &tmp_length, &tmp_ind);
663         if(tmp_length!=(guint32)tvb_reported_length_remaining(tvb, offset)){
664                 return 0;
665         }
666         /* then comes an INTEGER (version)*/
667         offset = get_ber_identifier(tvb, offset, &tmp_class, &tmp_pc, &tmp_tag);
668         if((tmp_class!=BER_CLASS_UNI)||(tmp_tag!=BER_UNI_TAG_INTEGER)){
669                 return 0;
670         }
671         /* do we need to test that version is 0 - 2 (version1-3) ? */
672
673
674         /*
675          * The first SNMP packet goes to the SNMP port; the second one
676          * may come from some *other* port, but goes back to the same
677          * IP address and port as the ones from which the first packet
678          * came; all subsequent packets presumably go between those two
679          * IP addresses and ports.
680          *
681          * If this packet went to the SNMP port, we check to see if
682          * there's already a conversation with one address/port pair
683          * matching the source IP address and port of this packet,
684          * the other address matching the destination IP address of this
685          * packet, and any destination port.
686          *
687          * If not, we create one, with its address 1/port 1 pair being
688          * the source address/port of this packet, its address 2 being
689          * the destination address of this packet, and its port 2 being
690          * wildcarded, and give it the SNMP dissector as a dissector.
691          */
692         if (pinfo->destport == UDP_PORT_SNMP) {
693           conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
694                                            pinfo->srcport, 0, NO_PORT_B);
695           if( (conversation == NULL) || (conversation->dissector_handle!=snmp_handle) ){
696             conversation = conversation_new(pinfo->fd->num, &pinfo->src, &pinfo->dst, PT_UDP,
697                                             pinfo->srcport, 0, NO_PORT2);
698             conversation_set_dissector(conversation, snmp_handle);
699           }
700         }
701
702         return dissect_snmp_pdu(tvb, 0, pinfo, tree, proto_snmp, ett_snmp, FALSE);
703 }
704 static void
705 dissect_snmp_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
706 {
707         int offset = 0;
708         guint message_len;
709
710         while (tvb_reported_length_remaining(tvb, offset) > 0) {
711                 message_len = dissect_snmp_pdu(tvb, 0, pinfo, tree,
712                     proto_snmp, ett_snmp, TRUE);
713                 if (message_len == 0) {
714                         /*
715                          * We don't have all the data for that message,
716                          * so we need to do desegmentation;
717                          * "dissect_snmp_pdu()" has set that up.
718                          */
719                         break;
720                 }
721                 offset += message_len;
722         }
723 }
724 static void
725 dissect_smux_pdu(tvbuff_t *tvb, int offset, packet_info *pinfo,
726     proto_tree *tree, int proto, gint ett)
727 {
728         /* FIX ME */
729 }
730 static void
731 dissect_smux(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
732 {
733         dissect_smux_pdu(tvb, 0, pinfo, tree, proto_smux, ett_smux);
734 }
735 static void
736 process_prefs(void)
737 {
738 #ifdef HAVE_SOME_SNMP
739         gchar *tmp_mib_modules;
740         static gboolean mibs_loaded = FALSE;
741
742         if (mibs_loaded) {
743                 /*
744                  * Unload the MIBs, as we'll be reloading them based on
745                  * the current preference setting.
746                  */
747                 shutdown_mib(); /* unload MIBs */
748         }
749
750         /*
751          * Cannot check if MIBS is already set, as it could be set by Ethereal.
752          *
753          * If we have a list of modules to load, put that list in MIBS,
754          * otherwise clear MIBS.
755          */
756         if (mib_modules != NULL) {
757                 tmp_mib_modules = g_strconcat("MIBS=", mib_modules, NULL);
758                 /*
759                  * Try to be clever and replace colons for semicolons under
760                  * Windows.  Do the converse on non-Windows systems.  This
761                  * handles cases where we've copied a preferences file
762                  * between a non-Windows box and a Windows box or upgraded
763                  * from an older version of Ethereal under Windows.
764                  */
765                 g_strdelimit(tmp_mib_modules, IMPORT_SEPARATOR, ENV_SEPARATOR_CHAR);
766
767 #ifdef _WIN32
768                 _putenv(tmp_mib_modules);
769 #else
770                 putenv(tmp_mib_modules);
771 #endif /*_WIN32*/
772         } else {
773 #ifdef _WIN32
774                 _putenv("MIBS");
775 #else
776                 putenv("MIBS");
777 #endif  /* _WIN32 */
778         }
779
780         /*
781          * Load the MIBs.
782          */
783         register_mib_handlers();
784         read_premib_configs();
785         init_mib();
786         read_configs();
787         mibs_loaded = TRUE;
788 #endif /* HAVE_SOME_SNMP */
789 }
790 /*--- proto_register_snmp -------------------------------------------*/
791 void proto_register_snmp(void) {
792
793 #if defined(_WIN32) && defined(HAVE_SOME_SNMP)
794         char *mib_path;
795         int mib_path_len;
796 #define MIB_PATH_APPEND "snmp\\mibs"
797 #endif
798         gchar *tmp_mib_modules;
799
800   /* List of fields */
801   static hf_register_info hf[] = {
802                 { &hf_snmp_v3_flags_auth,
803                 { "Authenticated", "snmp.v3.flags.auth", FT_BOOLEAN, 8,
804                     TFS(&flags_set_truth), TH_AUTH, "", HFILL }},
805                 { &hf_snmp_v3_flags_crypt,
806                 { "Encrypted", "snmp.v3.flags.crypt", FT_BOOLEAN, 8,
807                     TFS(&flags_set_truth), TH_CRYPT, "", HFILL }},
808                 { &hf_snmp_v3_flags_report,
809                 { "Reportable", "snmp.v3.flags.report", FT_BOOLEAN, 8,
810                     TFS(&flags_set_truth), TH_REPORT, "", HFILL }},
811                 { &hf_snmp_engineid_conform, {
812                     "Engine ID Conformance", "snmp.engineid.conform", FT_BOOLEAN, 8,
813                     TFS(&tfs_snmp_engineid_conform), F_SNMP_ENGINEID_CONFORM, "Engine ID RFC3411 Conformance", HFILL }},
814                 { &hf_snmp_engineid_enterprise, {
815                     "Engine Enterprise ID", "snmp.engineid.enterprise", FT_UINT32, BASE_DEC,
816                     VALS(sminmpec_values), 0, "Engine Enterprise ID", HFILL }},
817                 { &hf_snmp_engineid_format, {
818                     "Engine ID Format", "snmp.engineid.format", FT_UINT8, BASE_DEC,
819                     VALS(snmp_engineid_format_vals), 0, "Engine ID Format", HFILL }},
820                 { &hf_snmp_engineid_ipv4, {
821                     "Engine ID Data: IPv4 address", "snmp.engineid.ipv4", FT_IPv4, BASE_NONE,
822                     NULL, 0, "Engine ID Data: IPv4 address", HFILL }},
823                 { &hf_snmp_engineid_ipv6, {
824                     "Engine ID Data: IPv6 address", "snmp.engineid.ipv6", FT_IPv6, BASE_NONE,
825                     NULL, 0, "Engine ID Data: IPv6 address", HFILL }},
826                 { &hf_snmp_engineid_mac, {
827                     "Engine ID Data: MAC address", "snmp.engineid.mac", FT_ETHER, BASE_NONE,
828                     NULL, 0, "Engine ID Data: MAC address", HFILL }},
829                 { &hf_snmp_engineid_text, {
830                     "Engine ID Data: Text", "snmp.engineid.text", FT_STRING, BASE_NONE,
831                     NULL, 0, "Engine ID Data: Text", HFILL }},
832                 { &hf_snmp_engineid_time, {
833                     "Engine ID Data: Time", "snmp.engineid.time", FT_ABSOLUTE_TIME, BASE_NONE,
834                     NULL, 0, "Engine ID Data: Time", HFILL }},
835                 { &hf_snmp_engineid_data, {
836                     "Engine ID Data", "snmp.engineid.data", FT_BYTES, BASE_HEX,
837                     NULL, 0, "Engine ID Data", HFILL }},
838
839 #include "packet-snmp-hfarr.c"
840   };
841
842   /* List of subtrees */
843   static gint *ett[] = {
844           &ett_snmp,
845           &ett_engineid,
846           &ett_msgFlags,
847
848 #include "packet-snmp-ettarr.c"
849   };
850         module_t *snmp_module;
851
852   #ifdef HAVE_SOME_SNMP
853
854 #ifdef _WIN32
855         /* Set MIBDIRS so that the SNMP library can find its mibs. */
856         /* XXX - Should we set MIBS or MIBFILES as well? */
857         mib_path_len=strlen(get_datafile_dir()) + strlen(MIB_PATH_APPEND) + 20;
858         mib_path = ep_alloc (mib_path_len);
859         g_snprintf (mib_path, mib_path_len, "MIBDIRS=%s\\%s", get_datafile_dir(), MIB_PATH_APPEND);
860         /* Amazingly enough, Windows does not provide setenv(). */
861         if (getenv("MIBDIRS") == NULL)
862                 _putenv(mib_path);
863
864 #endif  /* _WIN32 */
865
866         /*
867          * Suppress warnings about unknown tokens - we aren't initializing
868          * UCD SNMP in its entirety, we're just initializing the
869          * MIB-handling part because that's all we're using, which
870          * means that entries in the configuration file for other
871          * pars of the library will not be handled, and we don't want
872          * the config file reading code to whine about that.
873          */
874         netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
875                                NETSNMP_DS_LIB_NO_TOKEN_WARNINGS, TRUE);
876         netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,
877                            NETSNMP_DS_LIB_PRINT_SUFFIX_ONLY, 2);
878 #endif /* HAVE_SOME_SNMP */
879
880
881   /* Register protocol */
882   proto_snmp = proto_register_protocol(PNAME, PSNAME, PFNAME);
883   new_register_dissector("snmp", dissect_snmp, proto_snmp);
884
885   /* Register fields and subtrees */
886   proto_register_field_array(proto_snmp, hf, array_length(hf));
887   proto_register_subtree_array(ett, array_length(ett));
888
889
890         /* Register configuration preferences */
891         snmp_module = prefs_register_protocol(proto_snmp, process_prefs);
892         prefs_register_bool_preference(snmp_module, "display_oid",
893                 "Show SNMP OID in info column",
894                 "Whether the SNMP OID should be shown in the info column",
895                 &display_oid);
896
897         /*
898          * Set the default value of "mib_modules".
899          *
900          * If the MIBS environment variable is set, make its value
901          * the value of "mib_modules", otherwise, set "mib_modules"
902          * to DEF_MIB_MODULES.
903          */
904         tmp_mib_modules = getenv("MIBS");
905         if (tmp_mib_modules != NULL)
906                 mib_modules = tmp_mib_modules;
907         prefs_register_string_preference(snmp_module, "mib_modules",
908             "MIB modules to load",
909             "List of MIB modules to load (the list is set to environment variable MIBS if the variable is not already set)"
910             "The list must be separated by colons (:) on non-Windows systems and semicolons (;) on Windows systems",
911             &mib_modules);
912         prefs_register_bool_preference(snmp_module, "desegment",
913             "Reassemble SNMP-over-TCP messages\nspanning multiple TCP segments",
914             "Whether the SNMP dissector should reassemble messages spanning multiple TCP segments."
915             " To use this option, you must also enable \"Allow subdissectors to reassemble TCP streams\" in the TCP protocol settings.",
916             &snmp_desegment);
917
918 }
919
920
921 /*--- proto_reg_handoff_snmp ---------------------------------------*/
922 void proto_reg_handoff_snmp(void) {
923         dissector_handle_t snmp_tcp_handle;
924
925         snmp_handle = find_dissector("snmp");
926
927         dissector_add("udp.port", UDP_PORT_SNMP, snmp_handle);
928         dissector_add("udp.port", UDP_PORT_SNMP_TRAP, snmp_handle);
929         dissector_add("ethertype", ETHERTYPE_SNMP, snmp_handle);
930         dissector_add("ipx.socket", IPX_SOCKET_SNMP_AGENT, snmp_handle);
931         dissector_add("ipx.socket", IPX_SOCKET_SNMP_SINK, snmp_handle);
932         dissector_add("hpext.dxsap", HPEXT_SNMP, snmp_handle);
933
934         snmp_tcp_handle = create_dissector_handle(dissect_snmp_tcp, proto_snmp);
935         dissector_add("tcp.port", TCP_PORT_SNMP, snmp_tcp_handle);
936         dissector_add("tcp.port", TCP_PORT_SNMP_TRAP, snmp_tcp_handle);
937
938         data_handle = find_dissector("data");
939
940         /*
941          * Process preference settings.
942          *
943          * We can't do this in the register routine, as preferences aren't
944          * read until all dissector register routines have been called (so
945          * that all dissector preferences have been registered).
946          */
947         process_prefs();
948
949 }
950
951 void
952 proto_register_smux(void)
953 {
954         static hf_register_info hf[] = {
955                 { &hf_smux_version,
956                 { "Version", "smux.version", FT_UINT8, BASE_DEC, NULL,
957                     0x0, "", HFILL }},
958                 { &hf_smux_pdutype,
959                 { "PDU type", "smux.pdutype", FT_UINT8, BASE_DEC, VALS(smux_types),
960                     0x0, "", HFILL }},
961         };
962         static gint *ett[] = {
963                 &ett_smux,
964         };
965
966         proto_smux = proto_register_protocol("SNMP Multiplex Protocol",
967             "SMUX", "smux");
968         proto_register_field_array(proto_smux, hf, array_length(hf));
969         proto_register_subtree_array(ett, array_length(ett));
970
971         variable_oid_dissector_table =
972             register_dissector_table("snmp.variable_oid",
973               "SNMP Variable OID", FT_STRING, BASE_NONE);
974 }
975
976 void
977 proto_reg_handoff_smux(void)
978 {
979         dissector_handle_t smux_handle;
980
981         smux_handle = create_dissector_handle(dissect_smux, proto_smux);
982         dissector_add("tcp.port", TCP_PORT_SMUX, smux_handle);
983 }
984
985