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