Fix from Ralf Schneider to the IS Neighbor dissection.
[obnox/wireshark/wip.git] / packet-isis-hello.c
1 /* packet-isis-hello.c
2  * Routines for decoding isis hello packets and their CLVs
3  *
4  * $Id: packet-isis-hello.c,v 1.5 2000/03/28 06:12:15 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 #include "packet.h"
41 #include "packet-isis.h"
42 #include "packet-isis-clv.h"
43 #include "packet-isis-hello.h"
44
45 /* hello packets */
46 static int proto_isis_hello = -1;
47 static int hf_isis_hello_circuit_reserved = -1;
48 static int hf_isis_hello_source_id = -1;
49 static int hf_isis_hello_holding_timer = -1;
50 static int hf_isis_hello_pdu_length = -1;
51 static int hf_isis_hello_priority_reserved = -1;
52 static int hf_isis_hello_lan_id = -1;
53 static int hf_isis_hello_local_circuit_id = -1;
54 static int hf_isis_hello_clv_ipv4_int_addr = -1;
55
56 static gint ett_isis_hello = -1;
57 static gint ett_isis_hello_clv_area_addr = -1;
58 static gint ett_isis_hello_clv_is_neighbors = -1;
59 static gint ett_isis_hello_clv_padding = -1;
60 static gint ett_isis_hello_clv_unknown = -1;
61 static gint ett_isis_hello_clv_nlpid = -1;
62 static gint ett_isis_hello_clv_auth = -1;
63 static gint ett_isis_hello_clv_ipv4_int_addr = -1;
64
65 static const value_string isis_hello_circuit_type_vals[] = {
66         { ISIS_HELLO_TYPE_RESERVED,     "Reserved 0 (discard PDU)"},
67         { ISIS_HELLO_TYPE_LEVEL_1,      "Level 1 only"},
68         { ISIS_HELLO_TYPE_LEVEL_2,      "Level 2 only"},
69         { ISIS_HELLO_TYPE_LEVEL_12,     "Level 1 and 2"},
70         { 0,            NULL} };
71
72 /* 
73  * Predclare dissectors for use in clv dissection.
74  */
75 static void dissect_hello_area_address_clv(const u_char *pd, int offset, 
76                 guint length, frame_data *fd, proto_tree *tree);
77 static void dissect_hello_is_neighbors_clv(const u_char *pd, int offset, 
78                 guint length, frame_data *fd, proto_tree *tree);
79 static void dissect_hello_padding_clv(const u_char *pd, int offset, 
80                 guint length, frame_data *fd, proto_tree *tree);
81 static void dissect_hello_nlpid_clv(const u_char *pd, int offset, 
82                 guint length, frame_data *fd, proto_tree *tree);
83 static void dissect_hello_ip_int_addr_clv(const u_char *pd, int offset, 
84                 guint length, frame_data *fd, proto_tree *tree);
85 static void dissect_hello_auth_clv(const u_char *pd, int offset, 
86                 guint length, frame_data *fd, proto_tree *tree);
87
88 static const isis_clv_handle_t clv_l1_hello_opts[] = {
89         {
90                 ISIS_CLV_L1H_AREA_ADDRESS,
91                 "Area address(es)",
92                 &ett_isis_hello_clv_area_addr,
93                 dissect_hello_area_address_clv
94         },
95         {
96                 ISIS_CLV_L1H_IS_NEIGHBORS,
97                 "IS Neighbor(s)",
98                 &ett_isis_hello_clv_is_neighbors,
99                 dissect_hello_is_neighbors_clv
100         },
101         {
102                 ISIS_CLV_L1H_PADDING,
103                 "Padding",
104                 &ett_isis_hello_clv_padding,
105                 dissect_hello_padding_clv
106         },
107         {
108                 ISIS_CLV_L1H_NLPID,
109                 "NLPID",
110                 &ett_isis_hello_clv_nlpid,
111                 dissect_hello_nlpid_clv
112         },
113         {
114                 ISIS_CLV_L1H_IP_INTERFACE_ADDR,
115                 "IP Interface address(es)",
116                 &ett_isis_hello_clv_ipv4_int_addr,
117                 dissect_hello_ip_int_addr_clv
118         },
119         {
120                 ISIS_CLV_L1H_AUTHENTICATION_NS,
121                 "Authentication(non spec)",
122                 &ett_isis_hello_clv_auth,
123                 dissect_hello_auth_clv
124         },
125         {
126                 ISIS_CLV_L1H_AUTHENTICATION,
127                 "Authentication",
128                 &ett_isis_hello_clv_auth,
129                 dissect_hello_auth_clv
130         },
131         {
132                 0,
133                 "",
134                 NULL,
135                 NULL
136         }
137 };
138
139 static const isis_clv_handle_t clv_l2_hello_opts[] = {
140         {
141                 ISIS_CLV_L2H_AREA_ADDRESS,
142                 "Area address(es)",
143                 &ett_isis_hello_clv_area_addr,
144                 dissect_hello_area_address_clv
145         },
146         {
147                 ISIS_CLV_L2H_IS_NEIGHBORS,
148                 "IS Neighbor(s)",
149                 &ett_isis_hello_clv_is_neighbors,
150                 dissect_hello_is_neighbors_clv
151         },
152         {
153                 ISIS_CLV_L2H_PADDING,
154                 "Padding",
155                 &ett_isis_hello_clv_padding,
156                 dissect_hello_padding_clv
157         },
158         {
159                 ISIS_CLV_L2H_NLPID,
160                 "NLPID",
161                 &ett_isis_hello_clv_nlpid,
162                 dissect_hello_nlpid_clv
163         },
164         {
165                 ISIS_CLV_L2H_IP_INTERFACE_ADDR,
166                 "IP Interface address(es)",
167                 &ett_isis_hello_clv_ipv4_int_addr,
168                 dissect_hello_ip_int_addr_clv
169         },
170         {
171                 ISIS_CLV_L2H_AUTHENTICATION_NS,
172                 "Authentication(non spec)",
173                 &ett_isis_hello_clv_auth,
174                 dissect_hello_auth_clv
175         },
176         {
177                 ISIS_CLV_L2H_AUTHENTICATION,
178                 "Authentication",
179                 &ett_isis_hello_clv_auth,
180                 dissect_hello_auth_clv
181         },
182         {
183                 0,
184                 "",
185                 NULL,
186                 NULL
187         }
188 };
189
190 static const isis_clv_handle_t clv_ptp_hello_opts[] = {
191         {
192                 ISIS_CLV_PTP_AREA_ADDRESS,
193                 "Area address(es)",
194                 &ett_isis_hello_clv_area_addr,
195                 dissect_hello_area_address_clv
196         },
197         {
198                 ISIS_CLV_PTP_PADDING,
199                 "Padding",
200                 &ett_isis_hello_clv_padding,
201                 dissect_hello_padding_clv
202         },
203         {
204                 ISIS_CLV_PTP_NLPID,
205                 "NLPID",
206                 &ett_isis_hello_clv_nlpid,
207                 dissect_hello_nlpid_clv
208         },
209         {
210                 ISIS_CLV_PTP_IP_INTERFACE_ADDR,
211                 "IP Interface address(es)",
212                 &ett_isis_hello_clv_ipv4_int_addr,
213                 dissect_hello_ip_int_addr_clv
214         },
215         {
216                 ISIS_CLV_PTP_AUTHENTICATION_NS,
217                 "Authentication(non spec)",
218                 &ett_isis_hello_clv_auth,
219                 dissect_hello_auth_clv
220         },
221         {
222                 ISIS_CLV_PTP_AUTHENTICATION,
223                 "Authentication",
224                 &ett_isis_hello_clv_auth,
225                 dissect_hello_auth_clv
226         },
227         {
228                 0,
229                 "",
230                 NULL,
231                 NULL
232         }
233 };
234
235 /*
236  * Name: dissect_hello_nlpid_clv()
237  *
238  * Description:
239  *      Decode for a hello packets NLPID clv.  Calls into the
240  *      clv common one.
241  *
242  * Input:
243  *      u_char * : packet data
244  *      int : current offset into packet data
245  *      guint : length of this clv
246  *      frame_data * : frame data
247  *      proto_tree * : proto tree to build on (may be null)
248  *
249  * Output:
250  *      void, will modify proto_tree if not null.
251  */
252 static void 
253 dissect_hello_nlpid_clv(const u_char *pd, int offset, 
254                 guint length, frame_data *fd, proto_tree *tree) {
255         isis_dissect_nlpid_clv(pd, offset, length, fd, tree );
256 }
257
258 /*
259  * Name: dissect_hello_ip_int_addr_clv()
260  *
261  * Description:
262  *      Decode for a hello packets ip interface addr clv.  Calls into the
263  *      clv common one.
264  *
265  * Input:
266  *      u_char * : packet data
267  *      int : current offset into packet data
268  *      guint : length of this clv
269  *      frame_data * : frame data
270  *      proto_tree * : proto tree to build on (may be null)
271  *
272  * Output:
273  *      void, will modify proto_tree if not null.
274  */
275 static void 
276 dissect_hello_ip_int_addr_clv(const u_char *pd, int offset, 
277                 guint length, frame_data *fd, proto_tree *tree) {
278         isis_dissect_ip_int_clv(pd, offset, length, fd, tree, 
279                 hf_isis_hello_clv_ipv4_int_addr );
280 }
281
282 /*
283  * Name: dissect_hello_auth_clv()
284  *
285  * Description:
286  *      Decode for a hello packets authenticaion clv.  Calls into the
287  *      clv common one.  An auth inside a hello packet is a perlink
288  *      password.
289  *
290  * Input:
291  *      u_char * : packet data
292  *      int : current offset into packet data
293  *      guint : length of this clv
294  *      frame_data * : frame data
295  *      proto_tree * : proto tree to build on (may be null)
296  *
297  * Output:
298  *      void, will modify proto_tree if not null.
299  */
300 static void 
301 dissect_hello_auth_clv(const u_char *pd, int offset, 
302                 guint length, frame_data *fd, proto_tree *tree) {
303         isis_dissect_authentication_clv(pd, offset, length, fd, tree, 
304                 "Per Link authentication" );
305 }
306
307 /*
308  * Name: dissect_hello_area_address_clv()
309  *
310  * Description:
311  *      Decode for a hello packets area address clv.  Calls into the
312  *      clv common one.
313  *
314  * Input:
315  *      u_char * : packet data
316  *      int : current offset into packet data
317  *      guint : length of this clv
318  *      frame_data * : frame data
319  *      proto_tree * : proto tree to build on (may be null)
320  *
321  * Output:
322  *      void, will modify proto_tree if not null.
323  */
324 static void 
325 dissect_hello_area_address_clv(const u_char *pd, int offset, 
326                 guint length, frame_data *fd, proto_tree *tree) {
327         isis_dissect_area_address_clv(pd, offset, length, fd, tree );
328 }
329
330 /*
331  * Name: isis_dissect_is_neighbors_clv()
332  * 
333  * Description:
334  *      Take apart a IS neighbor packet.  A neighbor is n 6 byte packets.
335  *      (they tend to be an 802.3 MAC address, but its not required).
336  *
337  * Input:
338  *      u_char * : packet data
339  *      int : offset into packet data where we are.
340  *      guint : length of clv we are decoding
341  *      frame_data * : frame data (complete frame)
342  *      proto_tree * : protocol display tree to fill out.  May be NULL
343  *      gint : tree id to use for proto tree.
344  * 
345  * Output:
346  *      void, but we will add to proto tree if !NULL.
347  */
348 void 
349 dissect_hello_is_neighbors_clv(const u_char *pd, int offset, 
350                 guint length, frame_data *fd, proto_tree *tree ) {
351         while ( length > 0 ) {
352                 if (length<6) {
353                         isis_dissect_unknown(offset, length, tree, fd, 
354                                 "short is neighbor (%d vs 6)", length );
355                         return;
356                 }
357                 /* 
358                  * Lets turn the area address into "standard" 0000.0000.etc
359                  * format string.  
360                  */
361                 if ( tree ) {
362                         proto_tree_add_text ( tree, offset, 6, 
363                                 "IS Neighbor: %02x%02x.%02x%02x.%02x%02x",
364                                 pd[offset], pd[offset+1], pd[offset+2],
365                                 pd[offset+3], pd[offset+4], pd[offset+5] );
366                 }
367                 offset += 6;
368                 length -= 6;
369         }
370 }
371
372
373 /*
374  * Name: dissect_hello_padding_clv()
375  *
376  * Description:
377  *      Decode for a hello packet's padding clv.  Padding does nothing,
378  *      so we just return.
379  *
380  * Input:
381  *      u_char * : packet data
382  *      int : current offset into packet data
383  *      guint : length of this clv
384  *      frame_data * : frame data
385  *      proto_tree * : proto tree to build on (may be null)
386  *
387  * Output:
388  *      void
389  */
390 static void 
391 dissect_hello_padding_clv(const u_char *pd, int offset, guint length, 
392                 frame_data *fd, proto_tree *tree) {
393         /* nothing to do here! */
394 }
395
396 /*
397  * Name: isis_dissect_isis_hello()
398  * 
399  * Description:
400  *      This procedure rips apart the various types of ISIS hellos.  L1H and
401  *      L2H's are identicle for the most part, while the PTP hello has
402  *      a shorter header.
403  *
404  * Input:
405  *      int : hello type, alla packet-isis.h ISIS_TYPE_* values
406  *      int : header length of packet.
407  *      u_char * : packet data
408  *      int offset : our offset into packet data.
409  *      frame_data * : frame data
410  *      proto_tree * : protocol display tree to add to.  May be NULL.
411  *
412  * Output:
413  *      void, will modify proto_tree if not NULL.
414  */     
415 void 
416 isis_dissect_isis_hello(int hello_type, int header_length, 
417                 const u_char *pd, int offset, frame_data *fd, proto_tree *tree){
418         isis_hello_t    *ihp;
419         proto_item      *ti;
420         proto_tree      *hello_tree = NULL;
421         int             len;
422         int             hlen;
423
424         if (hello_type == ISIS_TYPE_PTP_HELLO) {
425                 hlen = sizeof(*ihp) - 6;        /* make length correct */
426         } else {
427                 hlen = sizeof(*ihp);
428         }
429
430         if (!BYTES_ARE_IN_FRAME(offset, hlen)) {
431                 isis_dissect_unknown(offset, hlen, tree, fd,
432                         "not enough capture data for header (%d vs %d)",
433                         hlen, END_OF_FRAME);
434                 return;
435         }
436
437         ihp = (isis_hello_t *) &pd[offset];     
438
439         if (tree) {
440                 ti = proto_tree_add_item(tree, proto_isis_hello,
441                         offset, END_OF_FRAME, NULL);
442                 hello_tree = proto_item_add_subtree(ti, ett_isis_hello);
443                 proto_tree_add_uint_format(hello_tree, 
444                         hf_isis_hello_circuit_reserved,
445                         offset, 1, ihp->isis_hello_circuit_reserved,
446                         "Circuit type: %s, reserved(0x%02x == 0)",
447                                 val_to_str(ihp->isis_hello_circuit, 
448                                         isis_hello_circuit_type_vals,
449                                         "Unknown (0x%x)"),
450                                 ihp->isis_hello_creserved
451                         );
452
453                 proto_tree_add_string_format(hello_tree, hf_isis_hello_lan_id,
454                         offset + 1, 6, ihp->isis_hello_source_id,
455                         "Lan ID: %02x%02x.%02x%02x.%02x%02x",
456                                 ihp->isis_hello_lan_id[0],
457                                 ihp->isis_hello_lan_id[1],
458                                 ihp->isis_hello_lan_id[2],
459                                 ihp->isis_hello_lan_id[3],
460                                 ihp->isis_hello_lan_id[4],
461                                 ihp->isis_hello_lan_id[5]);
462                 proto_tree_add_item(hello_tree, hf_isis_hello_holding_timer,
463                         offset + 7, 2,pntohs(&ihp->isis_hello_holding_timer[0]));
464                 proto_tree_add_item(hello_tree, hf_isis_hello_pdu_length,
465                         offset + 9, 2,pntohs(&ihp->isis_hello_pdu_length[0]));
466                 proto_tree_add_uint_format(hello_tree, 
467                         hf_isis_hello_priority_reserved,
468                         offset + 11, 1, ihp->isis_hello_priority_reserved,
469                         "Priority: %d, reserved(0x%02x == 0)",
470                                 ihp->isis_hello_priority,
471                                 ihp->isis_hello_preserved );
472                 if (hello_type == ISIS_TYPE_PTP_HELLO) {
473                         proto_tree_add_item(hello_tree, 
474                                 hf_isis_hello_local_circuit_id,
475                                 offset + 12, 1, ihp->isis_hello_lan_id[0] );
476                 } else { 
477                         proto_tree_add_string_format(hello_tree, 
478                                 hf_isis_hello_lan_id, offset + 12, 7, 
479                                 ihp->isis_hello_lan_id,
480                                 "Lan ID: %02x%02x.%02x%02x.%02x%02x-%02d",
481                                         ihp->isis_hello_lan_id[0],
482                                         ihp->isis_hello_lan_id[1],
483                                         ihp->isis_hello_lan_id[2],
484                                         ihp->isis_hello_lan_id[3],
485                                         ihp->isis_hello_lan_id[4],
486                                         ihp->isis_hello_lan_id[5],
487                                         ihp->isis_hello_lan_id[6]);
488                 }
489         }
490
491         offset += hlen;
492         len = pntohs(&ihp->isis_hello_pdu_length[0]);
493         len -= header_length;
494         if (len < 0) {
495                 isis_dissect_unknown(offset, header_length, tree, fd, 
496                         "packet header length %d went beyond packet", 
497                         header_length );
498                 return;
499         }
500         /*
501          * Now, we need to decode our CLVs.  We need to pass in
502          * our list of valid ones!
503          */
504         if (hello_type == ISIS_TYPE_L1_HELLO){
505                 isis_dissect_clvs ( clv_l1_hello_opts, len, pd, offset, fd, 
506                         hello_tree, ett_isis_hello_clv_unknown );
507         } else if (hello_type == ISIS_TYPE_L2_HELLO) {
508                 isis_dissect_clvs ( clv_l2_hello_opts, len, pd, offset, fd, 
509                         hello_tree, ett_isis_hello_clv_unknown );
510         } else {
511                 isis_dissect_clvs ( clv_ptp_hello_opts, len, pd, offset, fd, 
512                         hello_tree, ett_isis_hello_clv_unknown );
513         }
514 }
515
516 /*
517  * Name: proto_register_isis_hello()
518  *
519  * Description:
520  *      Register our protocol sub-sets with protocol manager.
521  *      NOTE: this procedure is autolinked by the makefile process that
522  *              builds register.c
523  *
524  * Input: 
525  *      void
526  *
527  * Output:
528  *      void
529  */
530 void
531 proto_register_isis_hello(void) {
532         static hf_register_info hf[] = {
533                 { &hf_isis_hello_circuit_reserved,
534                 { "Circuit type",       "isis_hello.circuite_type",
535                         FT_UINT8, BASE_HEX, NULL, 0x0, "" }},
536
537                 { &hf_isis_hello_source_id,
538                 { "Source ID",          "isis_hello.source_id",
539                         FT_ETHER, BASE_HEX, NULL, 0x0, "" }},
540
541                 { &hf_isis_hello_holding_timer,
542                 { "Holding timer",      "isis_hello.holding_timer", 
543                         FT_UINT16, BASE_DEC, NULL, 0x0, "" }},
544
545                 { &hf_isis_hello_pdu_length,
546                 { "PDU length",           "isis_hello.pdu_length",
547                         FT_UINT16, BASE_DEC, NULL, 0x0, "" }},
548
549                 { &hf_isis_hello_priority_reserved,
550                  { "Priority",          "isis_hello.priority",FT_UINT8, BASE_DEC, NULL, 
551                   ISIS_HELLO_P_RESERVED_MASK, "" }},
552
553                 { &hf_isis_hello_lan_id,
554                 { "LAN ID", "isis_hello.lan_id", FT_STRING, BASE_DEC, NULL, 0x0, "" }},
555
556                 { &hf_isis_hello_local_circuit_id,
557                 { "Local circuit ID", "isis_hello.local_circuit_id", FT_UINT8,
558                    BASE_DEC, NULL, 0x0, "" }},
559
560                 { &hf_isis_hello_clv_ipv4_int_addr,
561                 { "IPv4 interface address", "isis_hello.clv_ipv4_int_addr", FT_IPv4,
562                    BASE_NONE, NULL, 0x0, "" }},
563
564         };
565         static gint *ett[] = {
566                 &ett_isis_hello,
567                 &ett_isis_hello_clv_area_addr,
568                 &ett_isis_hello_clv_is_neighbors,
569                 &ett_isis_hello_clv_padding,
570                 &ett_isis_hello_clv_unknown,
571                 &ett_isis_hello_clv_nlpid,
572                 &ett_isis_hello_clv_auth,
573                 &ett_isis_hello_clv_ipv4_int_addr,
574         };
575
576         proto_isis_hello = proto_register_protocol("ISIS hello", "isis_hello");
577         proto_register_field_array(proto_isis_hello, hf, array_length(hf));
578         proto_register_subtree_array(ett, array_length(ett));
579 }
580