step two in endpoint talkers cleanup
[obnox/wireshark/wip.git] / packet-isis-clv.c
1 /* packet-isis-clv.c
2  * Common CLV decode routines.
3  *
4  * $Id: packet-isis-clv.c,v 1.28 2003/06/04 08:46:35 guy Exp $
5  * Stuart Stanley <stuarts@mxmail.net>
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <string.h>
32 #include <glib.h>
33
34 #include <epan/packet.h>
35 #include "packet-osi.h"
36 #include "packet-isis.h"
37 #include "packet-isis-clv.h"
38 #include "nlpid.h"
39
40 static void
41 free_g_string(void *arg)
42 {
43         g_string_free(arg, TRUE);
44 }
45
46 /*
47  * Name: isis_dissect_area_address_clv()
48  *
49  * Description:
50  *      Take an area address CLV and display it pieces.  An area address
51  *      CLV is n, x byte hex strings.
52  *
53  * Input:
54  *      tvbuff_t * : tvbuffer for packet data
55  *      proto_tree * : protocol display tree to fill out.  May be NULL
56  *      int : offset into packet data where we are.
57  *      int : length of clv we are decoding
58  *
59  * Output:
60  *      void, but we will add to proto tree if !NULL.
61  */
62 void
63 isis_dissect_area_address_clv(tvbuff_t *tvb, proto_tree *tree, int offset,
64         int length)
65 {
66         int             arealen,area_idx;
67         GString         *gstr;
68
69         while ( length > 0 ) {
70                 arealen = tvb_get_guint8(tvb, offset);
71                 length--;
72                 if (length<=0) {
73                         isis_dissect_unknown(tvb, tree, offset,
74                                 "short address (no length for payload)");
75                         return;
76                 }
77                 if ( arealen > length) {
78                         isis_dissect_unknown(tvb, tree, offset,
79                                 "short address, packet says %d, we have %d left",
80                                 arealen, length );
81                         return;
82                 }
83
84                 if ( tree ) {
85                         /*
86                          * Lets turn the area address into "standard"
87                          * xx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx format string.
88                          * this is a private routine as the print_nsap_net in
89                          * epan/osi_utils.c is incomplete and we need only
90                          * a subset - actually some nice placing of dots ....
91                          *
92                          * We pick an initial size of 32 bytes.
93                          */
94                         gstr = g_string_sized_new(32);
95
96                         /*
97                          * Free the GString if we throw an exception.
98                          */
99                         CLEANUP_PUSH(free_g_string, gstr);
100
101                         for (area_idx = 0; area_idx < arealen; area_idx++) {
102                                 g_string_sprintfa(gstr, "%02x",
103                                     tvb_get_guint8(tvb, offset+area_idx+1));
104                                 if (((area_idx & 1) == 0) &&
105                                     (area_idx + 1 < arealen)) {
106                                         g_string_sprintfa(gstr, ".");
107                                 }
108                         }
109
110                         /* and spit it out */
111                         proto_tree_add_text ( tree, tvb, offset, arealen + 1,
112                                 "Area address (%d): %s", arealen, gstr->str );
113
114                         /*
115                          * We're done with the GString, so delete it and
116                          * get rid of the cleanup handler.
117                          */
118                         CLEANUP_CALL_AND_POP;
119                 }
120                 offset += arealen + 1;
121                 length -= arealen;      /* length already adjusted for len fld*/
122         }
123 }
124
125
126 /*
127  * Name: isis_dissect_authentication_clv()
128  *
129  * Description:
130  *      Take apart the CLV that hold authentication information.  This
131  *      is currently 1 octet auth type (which must be 1) and then
132  *      the clear text password.
133  *
134  *      An ISIS password has different meaning depending where it
135  *      is found.  Thus we support a passed in prefix string to
136  *      use to name this.
137  *
138  * Input:
139  *      tvbuff_t * : tvbuffer for packet data
140  *      proto_tree * : protocol display tree to fill out.  May be NULL
141  *      int : offset into packet data where we are.
142  *      int : length of clv we are decoding
143  *      char * : Password meaning
144  *
145  * Output:
146  *      void, but we will add to proto tree if !NULL.
147  */
148 void
149 isis_dissect_authentication_clv(tvbuff_t *tvb, proto_tree *tree, int offset,
150         int length, char *meaning)
151 {
152         guchar pw_type;
153         int auth_unsupported;
154         GString *gstr;
155
156         if ( length <= 0 ) {
157                 return;
158         }
159
160         pw_type = tvb_get_guint8(tvb, offset);
161         offset += 1;
162         length--;
163         auth_unsupported = FALSE;
164
165         gstr = g_string_new("");
166
167         /*
168          * Free the GString if we throw an exception.
169          */
170         CLEANUP_PUSH(free_g_string, gstr);
171
172         switch (pw_type) {
173         case 1:
174                 g_string_sprintfa(gstr,
175                     "clear text (1), password (length %d) = ", length);
176                 if ( length > 0 ) {
177                   g_string_sprintfa(gstr, "%s",
178                     tvb_format_text(tvb, offset, length));
179                 } else {
180                   g_string_append(gstr, "no clear-text password found!!!");
181                 }
182                 break;
183         case 54:
184                 g_string_sprintfa(gstr,
185                     "hmac-md5 (54), password (length %d) = ", length);
186
187                 if ( length == 16 ) {
188                   g_string_sprintfa(gstr, "0x%02x", tvb_get_guint8(tvb, offset));
189                   offset += 1;
190                   length--;
191                   while (length > 0) {
192                     g_string_sprintfa(gstr, "%02x", tvb_get_guint8(tvb, offset));
193                     offset += 1;
194                     length--;
195                   }
196                 } else {
197                   g_string_append(gstr,
198                       "illegal hmac-md5 digest format (must be 16 bytes)");
199                 }
200                 break;
201         default:
202                 g_string_sprintfa(gstr, "type 0x%02x (0x%02x): ", pw_type, length );
203                 auth_unsupported=TRUE;
204                 break;
205         }
206
207         proto_tree_add_text ( tree, tvb, offset - 1, length + 1,
208                         "%s %s", meaning, gstr->str );
209
210         /*
211          * We're done with the GString, so delete it and get rid of
212          * the cleanup handler.
213          */
214         CLEANUP_CALL_AND_POP;
215
216         if ( auth_unsupported ) {
217                 isis_dissect_unknown(tvb, tree, offset,
218                         "Unknown authentication type" );
219         }
220 }
221
222 /*
223  * Name: isis_dissect_hostname_clv()
224  *
225  * Description:
226  *      dump the hostname information found in TLV 137
227  *      pls note that the hostname is not null terminated
228  *
229  * Input:
230  *      tvbuff_t * : tvbuffer for packet data
231  *      proto_tree * : protocol display tree to fill out.  May be NULL
232  *      int : offset into packet data where we are.
233  *      int : length of clv we are decoding
234  *
235  * Output:
236  *      void, but we will add to proto tree if !NULL.
237  */
238
239
240 void
241 isis_dissect_hostname_clv(tvbuff_t *tvb, proto_tree *tree, int offset,
242         int length)
243 {
244         if ( !tree ) return;            /* nothing to do! */
245
246         if ( length == 0 ) {
247                 proto_tree_add_text ( tree, tvb, offset, length,
248                         "Hostname: --none--" );
249         } else {
250                 proto_tree_add_text ( tree, tvb, offset, length,
251                         "Hostname: %.*s", length,
252                         tvb_get_ptr(tvb, offset, length) );
253         }
254 }
255
256
257
258
259 void
260 isis_dissect_mt_clv(tvbuff_t *tvb, proto_tree *tree, int offset, int length,
261         int tree_id)
262 {
263         guint16 mt_block;
264         char mt_desc[60];
265
266         while (length>0) {
267             /* length can only be a multiple of 2, otherwise there is
268                something broken -> so decode down until length is 1 */
269             if (length!=1) {
270                 /* fetch two bytes */
271                 mt_block=tvb_get_ntohs(tvb, offset);
272
273                 /* mask out the lower 12 bits */
274                 switch(mt_block&0x0fff) {
275                 case 0:
276                     strcpy(mt_desc,"IPv4 unicast");
277                     break;
278                 case 1:
279                     strcpy(mt_desc,"In-Band Management");
280                     break;
281                 case 2:
282                     strcpy(mt_desc,"IPv6 unicast");
283                     break;
284                 case 3:
285                     strcpy(mt_desc,"Multicast");
286                     break;
287                 case 4095:
288                     strcpy(mt_desc,"Development, Experimental or Proprietary");
289                     break;
290                 default:
291                     strcpy(mt_desc,"Reserved for IETF Consensus");
292                     break;
293                 }
294                 proto_tree_add_uint_format ( tree, tree_id, tvb, offset, 2,
295                         mt_block,
296                         "%s Topology (0x%03x)%s%s",
297                                       mt_desc,
298                                       mt_block&0xfff,
299                                       (mt_block&0x8000) ? "" : ", no sub-TLVs present",
300                                       (mt_block&0x4000) ? ", ATT bit set" : "" );
301             } else {
302                 proto_tree_add_text ( tree, tvb, offset, 1,
303                         "malformed MT-ID");
304                 break;
305             }
306             length=length-2;
307             offset=offset+2;
308         }
309 }
310
311
312 /*
313  * Name: isis_dissect_ip_int_clv()
314  *
315  * Description:
316  *      Take apart the CLV that lists all the IP interfaces.  The
317  *      meaning of which is slightly different for the different base packet
318  *      types, but the display is not different.  What we have is n ip
319  *      addresses, plain and simple.
320  *
321  * Input:
322  *      tvbuff_t * : tvbuffer for packet data
323  *      proto_tree * : protocol display tree to fill out.  May be NULL
324  *      int : offset into packet data where we are.
325  *      int : length of clv we are decoding
326  *      int : tree id to use for proto tree.
327  *
328  * Output:
329  *      void, but we will add to proto tree if !NULL.
330  */
331 void
332 isis_dissect_ip_int_clv(tvbuff_t *tvb, proto_tree *tree, int offset,
333         int length, int tree_id)
334 {
335         if ( length <= 0 ) {
336                 return;
337         }
338
339         while ( length > 0 ) {
340                 if ( length < 4 ) {
341                         isis_dissect_unknown(tvb, tree, offset,
342                                 "Short IP interface address (%d vs 4)",length );
343                         return;
344                 }
345
346                 if ( tree ) {
347                         proto_tree_add_item(tree, tree_id, tvb, offset, 4, FALSE);
348                 }
349                 offset += 4;
350                 length -= 4;
351         }
352 }
353
354 /*
355  * Name: isis_dissect_ipv6_int_clv()
356  *
357  * Description:
358  *      Take apart the CLV that lists all the IPv6 interfaces.  The
359  *      meaning of which is slightly different for the different base packet
360  *      types, but the display is not different.  What we have is n ip
361  *      addresses, plain and simple.
362  *
363  * Input:
364  *      tvbuff_t * : tvbuffer for packet data
365  *      proto_tree * : protocol display tree to fill out.  May be NULL
366  *      int : offset into packet data where we are.
367  *      int : length of clv we are decoding
368  *      int : tree id to use for proto tree.
369  *
370  * Output:
371  *      void, but we will add to proto tree if !NULL.
372  */
373 void
374 isis_dissect_ipv6_int_clv(tvbuff_t *tvb, proto_tree *tree, int offset,
375         int length, int tree_id)
376 {
377         guint8 addr [16];
378
379         if ( length <= 0 ) {
380                 return;
381         }
382
383         while ( length > 0 ) {
384                 if ( length < 16 ) {
385                         isis_dissect_unknown(tvb, tree, offset,
386                                 "Short IPv6 interface address (%d vs 16)",length );
387                         return;
388                 }
389                 tvb_memcpy(tvb, addr, offset, sizeof(addr));
390                 if ( tree ) {
391                         proto_tree_add_ipv6(tree, tree_id, tvb, offset, 16, addr);
392                 }
393                 offset += 16;
394                 length -= 16;
395         }
396 }
397
398
399 /*
400  * Name: isis_dissect_te_router_id_clv()
401  *
402  * Description:
403  *      Display the Traffic Engineering Router ID TLV #134.
404  *      This TLV is like the IP Interface TLV, except that
405  *      only _one_ IP address is present
406  *
407  * Input:
408  *      tvbuff_t * : tvbuffer for packet data
409  *      proto_tree * : protocol display tree to fill out.  May be NULL
410  *      int : offset into packet data where we are.
411  *      int : length of clv we are decoding
412  *      int : tree id to use for proto tree.
413  *
414  * Output:
415  *      void, but we will add to proto tree if !NULL.
416  */
417 void
418 isis_dissect_te_router_id_clv(tvbuff_t *tvb, proto_tree *tree, int offset,
419         int length, int tree_id)
420 {
421         if ( length <= 0 ) {
422                 return;
423         }
424
425         if ( length != 4 ) {
426                 isis_dissect_unknown(tvb, tree, offset,
427                         "malformed Traffic Engineering Router ID (%d vs 4)",length );
428                 return;
429         }
430         if ( tree ) {
431                 proto_tree_add_item(tree, tree_id, tvb, offset, 4, FALSE);
432         }
433 }
434
435 /*
436  * Name: isis_dissect_nlpid_clv()
437  *
438  * Description:
439  *      Take apart a NLPID packet and display it.  The NLPID (for intergrated
440  *      ISIS, contains n network layer protocol IDs that the box supports.
441  *      Our display buffer we use is upto 255 entries, 6 bytes per (0x00, )
442  *      plus 1 for zero termination.  We just just 256*6 for simplicity.
443  *
444  * Input:
445  *      tvbuff_t * : tvbuffer for packet data
446  *      proto_tree * : protocol display tree to fill out.  May be NULL
447  *      int : offset into packet data where we are.
448  *      int : length of clv we are decoding
449  *
450  * Output:
451  *      void, but we will add to proto tree if !NULL.
452  */
453 void
454 isis_dissect_nlpid_clv(tvbuff_t *tvb, proto_tree *tree, int offset, int length)
455 {
456         char sbuf[256*6];
457         char *s = sbuf;
458         int hlen = length;
459         int old_offset = offset;
460
461         if ( !tree ) return;            /* nothing to do! */
462
463         while ( length-- > 0 ) {
464                 if (s != sbuf ) {
465                         s += sprintf ( s, ", " );
466                 }
467                 s += sprintf ( s, "%s (0x%02x)",
468                     val_to_str(tvb_get_guint8(tvb, offset), nlpid_vals,
469                         "Unknown"), tvb_get_guint8(tvb, offset));
470                 offset++;
471         }
472
473         if ( hlen == 0 ) {
474                 sprintf ( sbuf, "--none--" );
475         }
476
477         proto_tree_add_text ( tree, tvb, old_offset, hlen,
478                         "NLPID(s): %s", sbuf );
479 }
480
481 /*
482  * Name: isis_dissect_clvs()
483  *
484  * Description:
485  *      Dispatch routine to shred all the CLVs in a packet.  We just
486  *      walk through the clv entries in the packet.  For each one, we
487  *      search the passed in valid clv's for this protocol (opts) for
488  *      a matching code.  If found, we add to the display tree and
489  *      then call the dissector.  If it is not, we just post an
490  *      "unknown" clv entry using the passed in unknown clv tree id.
491  *
492  * Input:
493  *      tvbuff_t * : tvbuffer for packet data
494  *      proto_tree * : protocol display tree to fill out.  May be NULL
495  *      int : offset into packet data where we are.
496  *      isis_clv_handle_t * : NULL dissector terminated array of codes
497  *              and handlers (along with tree text and tree id's).
498  *      int : length of CLV area.
499  *      int : length of IDs in packet.
500  *      int : unknown clv tree id
501  *
502  * Output:
503  *      void, but we will add to proto tree if !NULL.
504  */
505 void
506 isis_dissect_clvs(tvbuff_t *tvb, proto_tree *tree, int offset,
507         const isis_clv_handle_t *opts, int len, int id_length,
508         int unknown_tree_id)
509 {
510         guint8 code;
511         guint8 length;
512         int q;
513         proto_item      *ti;
514         proto_tree      *clv_tree;
515         int             adj;
516
517         while ( len > 0 ) {
518                 code = tvb_get_guint8(tvb, offset);
519                 offset += 1;
520
521                 length = tvb_get_guint8(tvb, offset);
522                 offset += 1;
523
524                 adj = (sizeof(code) + sizeof(length) + length);
525                 len -= adj;
526                 if ( len < 0 ) {
527                         isis_dissect_unknown(tvb, tree, offset,
528                                 "Short CLV header (%d vs %d)",
529                                 adj, len + adj );
530                         return;
531                 }
532                 q = 0;
533                 while ((opts[q].dissect != NULL )&&( opts[q].optcode != code )){
534                         q++;
535                 }
536                 if ( opts[q].dissect ) {
537                         if (tree) {
538                                 /* adjust by 2 for code/len octets */
539                                 ti = proto_tree_add_text(tree, tvb, offset - 2,
540                                         length + 2, "%s (%u)",
541                                         opts[q].tree_text, length );
542                                 clv_tree = proto_item_add_subtree(ti,
543                                         *opts[q].tree_id );
544                         } else {
545                                 clv_tree = NULL;
546                         }
547                         opts[q].dissect(tvb, clv_tree, offset,
548                                 id_length, length);
549                 } else {
550                         if (tree) {
551                                 ti = proto_tree_add_text(tree, tvb, offset - 2,
552                                         length + 2, "Unknown code %u (%u)",
553                                         code, length);
554                                 clv_tree = proto_item_add_subtree(ti,
555                                         unknown_tree_id );
556                         } else {
557                                 clv_tree = NULL;
558                         }
559                 }
560                 offset += length;
561         }
562 }