Assorted ISIS enhancements from Hannes Gredler.
[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.10 2001/04/16 10:04:30 guy Exp $
5  * Stuart Stanley <stuarts@mxmail.net>
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@zing.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  *
26  *
27  */
28
29 #ifdef HAVE_CONFIG_H
30 # include "config.h"
31 #endif
32
33 #ifdef HAVE_SYS_TYPES_H
34 # include <sys/types.h>
35 #endif
36
37 #include <stdio.h>
38 #include <string.h>
39 #include <glib.h>
40
41 #ifdef NEED_SNPRINTF_H
42 # include "snprintf.h"
43 #endif
44
45 #include "packet.h"
46 #include "packet-osi.h"
47 #include "packet-isis.h"
48 #include "packet-isis-clv.h"
49 #include "nlpid.h"
50
51
52 /*
53  * Name: isis_dissect_area_address_clv()
54  * 
55  * Description:
56  *      Take an area address CLV and display it pieces.  An area address
57  *      CLV is n, x byte hex strings.
58  *
59  * Input:
60  *      u_char * : packet data
61  *      int : offset into packet data where we are.
62  *      guint : length of clv we are decoding
63  *      frame_data * : frame data (complete frame)
64  *      proto_tree * : protocol display tree to fill out.  May be NULL
65  * 
66  * Output:
67  *      void, but we will add to proto tree if !NULL.
68  */
69 void 
70 isis_dissect_area_address_clv(const u_char *pd, int offset, 
71                 guint length, frame_data *fd, proto_tree *tree ) {
72         char            *sbuf;
73         int             mylen;
74
75         while ( length > 0 ) {
76                 mylen = pd[offset];
77                 length--;
78                 if (length<=0) {
79                         isis_dissect_unknown( offset, length, tree, fd,
80                                 "short address (no length for payload)");
81                         return;
82                 }
83                 if ( mylen > length) {
84                         isis_dissect_unknown(offset, length, tree, fd, 
85                                 "short address, packet say %d, we have %d left",
86                                 mylen, length );
87                         return;
88                 }
89
90                 /* 
91                  * Lets turn the area address into "standard" 0000.0000.etc
92                  * format string.  
93                  */
94 /*              sbuf = isis_address_to_string ( pd, offset + 1, mylen );*/
95       sbuf = print_nsap_net( pd + offset + 1, mylen );
96                 /* and spit it out */
97                 if ( tree ) {
98                         proto_tree_add_text ( tree, NullTVB, offset, mylen + 1,  
99                                 "Area address (%d): %s", mylen, sbuf );
100                 }
101                 offset += mylen + 1;
102                 length -= mylen;        /* length already adjusted for len fld*/
103         }
104 }
105
106
107 /*
108  * Name: isis_dissect_authentication_clv()
109  * 
110  * Description:
111  *      Take apart the CLV that hold authentication information.  This
112  *      is currently 1 octet auth type (which must be 1) and then
113  *      the clear text password.
114  *      
115  *      An ISIS password has different meaning depending where it
116  *      is found.  Thus we support a passed in prefix string to 
117  *      use to name this.
118  *
119  * Input:
120  *      u_char * : packet data
121  *      int : offset into packet data where we are.
122  *      guint : length of clv we are decoding
123  *      frame_data * : frame data (complete frame)
124  *      proto_tree * : protocol display tree to fill out.  May be NULL
125  *      char * : Password meaning
126  * 
127  * Output:
128  *      void, but we will add to proto tree if !NULL.
129  */
130 void 
131 isis_dissect_authentication_clv(const u_char *pd, int offset, guint length, 
132                 frame_data *fd, proto_tree *tree, char *meaning) {
133         u_char pw_type;
134         char sbuf[300];         /* 255 + header info area */
135         char *s = sbuf;
136         int use_cleartext;
137
138         if ( length <= 0 ) {
139                 return;
140         }
141
142         pw_type = pd[offset++];
143         length--;
144         use_cleartext = FALSE;
145         switch (pw_type) {
146         case 1:
147                 s += sprintf ( s, "type 1, clear text"  );
148                 use_cleartext = TRUE;
149                 break;
150         default:
151                 s += sprintf ( s, "type 0x%02x, (must be 1)", pw_type );
152                 break;
153         }
154
155         s += sprintf ( s, " (0x%02x): ", length );
156
157         if ( use_cleartext ) {
158                 if ( length > 0 ) {
159                         strncpy(s, &pd[offset], length);
160                         /* null terminate */
161                         s[length] = 0;
162                 } else {
163                         strcat(s, "<<no password found!!!>>" );
164                 }
165         /* NOTE, s no longer valid */
166         }
167         proto_tree_add_text ( tree, NullTVB, offset - 1, length + 1,
168                         "%s %s", meaning, sbuf );
169         if ( !use_cleartext ) {
170                 if ( length ) {
171                         isis_dissect_unknown(offset, length, tree, fd,
172                                 "Unknown autheticion type" );
173                 }
174         }
175 }
176
177 /*
178  * Name: isis_dissect_hostname_clv()
179  *
180  * Description:
181  *      dump the hostname information found in TLV 137
182  *      pls note that the hostname is not null terminated
183  *
184  * Input:
185  *      u_char * : packet data
186  *      int : offset into packet data where we are.
187  *      guint : length of clv we are decoding
188  *      frame_data * : frame data (complete frame)
189  *      proto_tree * : protocol display tree to fill out.  May be NULL
190  *      char * : Password meaning
191  *
192  * Output:
193  *      void, but we will add to proto tree if !NULL.
194  */
195
196
197 void
198 isis_dissect_hostname_clv(const u_char *pd, int offset,
199                 guint length, frame_data *fd, proto_tree *tree ) {
200         char sbuf[256*6];
201         char *s = sbuf;
202         int hlen = length;
203         int old_offset = offset;
204
205
206         if ( !tree ) return;            /* nothing to do! */
207
208         memcpy ( s, &pd[offset], hlen);
209         sbuf[hlen] = 0;                 /* don't forget null termination */
210
211         if ( hlen == 0 ) {
212                 sprintf ( sbuf, "--none--" );
213         }
214
215         proto_tree_add_text ( tree, NullTVB, old_offset, hlen,
216                         "Hostname: %s", sbuf );
217 }
218
219
220
221
222
223 /*
224  * Name: isis_dissect_ip_int_clv()
225  * 
226  * Description:
227  *      Take apart the CLV that lists all the IP interfaces.  The
228  *      meaning of which is slightly different for the different base packet
229  *      types, but the display is not different.  What we have is n ip
230  *      addresses, plain and simple.
231  *
232  * Input:
233  *      u_char * : packet data
234  *      int : offset into packet data where we are.
235  *      guint : length of clv we are decoding
236  *      frame_data * : frame data (complete frame)
237  *      proto_tree * : protocol display tree to fill out.  May be NULL
238  *      gint : tree id to use for proto tree.
239  * 
240  * Output:
241  *      void, but we will add to proto tree if !NULL.
242  */
243 void 
244 isis_dissect_ip_int_clv(const u_char *pd, int offset, 
245                 guint length, frame_data *fd, proto_tree *tree, gint tree_id ) {
246         guint32 addr;
247         if ( length <= 0 ) {
248                 return;
249         }
250
251         while ( length > 0 ) {
252                 if ( length < 4 ) {
253                         isis_dissect_unknown(offset, length, tree, fd,
254                                 "Short ip interface address (%d vs 4)",length );
255                         return;
256                 }
257                 memcpy(&addr, &pd[offset], sizeof(addr));
258                 if ( tree ) {
259                         proto_tree_add_ipv4(tree, tree_id, NullTVB, offset, 4, addr);
260                 }
261                 offset += 4;
262                 length -= 4;
263         }
264 }
265
266
267 /*
268  * Name: isis_dissect_te_router_id_clv()
269  *
270  * Description:
271  *      Display the Traffic Engineering Router ID TLV #134.
272  *      This TLV is like the IP Interface TLV, except that
273  *      only _one_ IP address is present
274  *
275  * Input:
276  *      u_char * : packet data
277  *      int : offset into packet data where we are.
278  *      guint : length of clv we are decoding
279  *      frame_data * : frame data (complete frame)
280  *      proto_tree * : protocol display tree to fill out.  May be NULL
281  *      gint : tree id to use for proto tree.
282  *
283  * Output:
284  *      void, but we will add to proto tree if !NULL.
285  */
286 void
287 isis_dissect_te_router_id_clv(const u_char *pd, int offset,
288                 guint length, frame_data *fd, proto_tree *tree, gint tree_id ) {
289         guint32 addr;
290         if ( length <= 0 ) {
291                 return;
292         }
293
294         if ( length != 4 ) {
295                 isis_dissect_unknown(offset, length, tree, fd,
296                         "malformed Traffic Engineering Router ID (%d vs 4)",length );
297                 return;
298         }
299         memcpy(&addr, &pd[offset], sizeof(addr));
300         if ( tree ) {
301                 proto_tree_add_ipv4(tree, tree_id, NullTVB, offset, 4, addr);
302         }
303 }
304
305 /*
306  * Name: isis_dissect_nlpid_clv()
307  * 
308  * Description:
309  *      Take apart a NLPID packet and display it.  The NLPID (for intergrated
310  *      ISIS, contains n network layer protocol IDs that the box supports.
311  *      Our display buffer we use is upto 255 entries, 6 bytes per (0x00, )
312  *      plus 1 for zero termination.  We just just 256*6 for simplicity.
313  *
314  * Input:
315  *      u_char * : packet data
316  *      int : offset into packet data where we are.
317  *      guint : length of clv we are decoding
318  *      frame_data * : frame data (complete frame)
319  *      proto_tree * : protocol display tree to fill out.  May be NULL
320  * 
321  * Output:
322  *      void, but we will add to proto tree if !NULL.
323  */
324 void 
325 isis_dissect_nlpid_clv(const u_char *pd, int offset, 
326                 guint length, frame_data *fd, proto_tree *tree ) {
327         char sbuf[256*6];
328         char *s = sbuf;
329         int hlen = length;
330         int old_offset = offset;
331
332         if ( !tree ) return;            /* nothing to do! */
333
334         while ( length-- > 0 ) {
335                 if (s != sbuf ) {
336                         s += sprintf ( s, ", " ); 
337                 }
338                 s += sprintf ( s, "%s (0x%02x)",
339                     val_to_str(pd[offset], nlpid_vals, "Unknown"), pd[offset]);
340                 offset++;       
341         }
342
343         if ( hlen == 0 ) {
344                 sprintf ( sbuf, "--none--" );
345         }
346
347         proto_tree_add_text ( tree, NullTVB, old_offset, hlen,
348                         "NLPID(s): %s", sbuf );
349 }
350
351 /*
352  * Name: isis_dissect_clvs()
353  * 
354  * Description:
355  *      Dispatch routine to shred all the CLVs in a packet.  We just
356  *      walk through the clv entries in the packet.  For each one, we
357  *      search the passed in valid clv's for this protocol (opts) for
358  *      a matching code.  If found, we add to the display tree and
359  *      then call the dissector.  If it is not, we just post an
360  *      "unknown" clv entrie using the passed in unknown clv tree id.
361  *
362  * Input:
363  *      isis_clv_handle_t * : NULL dissector terminated array of codes
364  *              and handlers (along with tree text and tree id's).
365  *      int : length of CLV area.
366  *      u_char * : packet data
367  *      int : offset into packet data where we are.
368  *      guint : length of clv we are decoding
369  *      frame_data * : frame data (complete frame)
370  *      proto_tree * : protocol display tree to fill out.  May be NULL
371  *      gint : unknown clv tree id
372  * 
373  * Output:
374  *      void, but we will add to proto tree if !NULL.
375  */
376 void 
377 isis_dissect_clvs(const isis_clv_handle_t *opts, int len, int id_length,
378                 const u_char *pd, int offset, frame_data *fd, proto_tree *tree,
379                 gint unknown_tree_id ) { 
380         guint8 code;
381         guint8 length;
382         int q;
383         proto_item      *ti;
384         proto_tree      *clv_tree;
385         char            sbuf[255];
386         int             adj;
387
388         while ( len > 0 ) {
389                 code = pd[offset++];
390                 length = pd[offset++];
391                 adj = (sizeof(code) + sizeof(length) + length);
392                 len -= adj;
393                 if ( len < 0 || !BYTES_ARE_IN_FRAME(offset, length) ) {
394                         isis_dissect_unknown(offset, adj, tree, fd,
395                                 "Short CLV header (%d vs %d)",
396                                 adj, len + adj );
397                         return;
398                 }
399                 q = 0;
400                 while ((opts[q].dissect != NULL )&&( opts[q].optcode != code )){
401                         q++;
402                 }
403                 if ( opts[q].dissect ) {
404                         if (tree) {
405                                 /* adjust by 2 for code/len octets */
406                                 snprintf ( sbuf, sizeof(sbuf), "%s (%d)", 
407                                         opts[q].tree_text, length ); 
408                                 ti = proto_tree_add_text(tree, NullTVB, offset - 2, 
409                                         length + 2, sbuf);
410                                 clv_tree = proto_item_add_subtree(ti, 
411                                         *opts[q].tree_id );
412                         } else {
413                                 clv_tree = NULL;
414                         }
415                         opts[q].dissect(pd, offset, length, id_length, fd,
416                                 clv_tree );
417                 } else {
418                         if (tree) { 
419                                 snprintf ( sbuf, sizeof(sbuf), 
420                                         "Unknown code (%d:%d)", code, length ); 
421                                 ti = proto_tree_add_text(tree, NullTVB, offset - 2, 
422                                         length + 2, sbuf);
423                                 clv_tree = proto_item_add_subtree(ti, 
424                                         unknown_tree_id );
425                         } else { 
426                                 clv_tree = NULL;
427                         }
428                 }
429                 offset += length;
430         }
431 }