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