added some options and enhancements to the print output:
[obnox/wireshark/wip.git] / packet-nlsp.c
1 /* packet-nlsp.c
2  * Routines for NetWare Link Services Protocol
3  *
4  * $Id: packet-nlsp.c,v 1.7 2003/10/06 08:35:30 guy Exp $
5  *
6  * Based on ISIS dissector by Stuart Stanley <stuarts@mxmail.net>
7  *
8  * Ethereal - Network traffic analyzer
9  * By Gerald Combs <gerald@ethereal.com>
10  * Copyright 1998 Gerald Combs
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 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <stdio.h>
32 #include <string.h>
33 #include <glib.h>
34 #include <epan/packet.h>
35 #include "packet-ipx.h"
36
37 /* NLSP base header */
38 static int proto_nlsp                    = -1;
39
40 static int hf_nlsp_irpd                  = -1;
41 static int hf_nlsp_header_length         = -1;
42 static int hf_nlsp_minor_version         = -1;
43 static int hf_nlsp_nr                    = -1;
44 static int hf_nlsp_type                  = -1;
45 static int hf_nlsp_major_version         = -1;
46 static int hf_nlsp_packet_length         = -1;
47 static int hf_nlsp_hello_state           = -1;
48 static int hf_nlsp_hello_multicast       = -1;
49 static int hf_nlsp_hello_circuit_type    = -1;
50 static int hf_nlsp_hello_holding_timer   = -1;
51 static int hf_nlsp_hello_priority        = -1;
52 static int hf_nlsp_lsp_sequence_number   = -1;
53 static int hf_nlsp_lsp_checksum          = -1;
54 static int hf_nlsp_lsp_p                 = -1;
55 static int hf_nlsp_lsp_attached_flag     = -1;
56 static int hf_nlsp_lsp_lspdbol           = -1;
57 static int hf_nlsp_lsp_router_type       = -1;
58
59 static gint ett_nlsp                     = -1;
60 static gint ett_nlsp_hello_clv_area_addr = -1;
61 static gint ett_nlsp_hello_clv_neighbors = -1;
62 static gint ett_nlsp_hello_local_mtu     = -1;
63 static gint ett_nlsp_hello_clv_unknown   = -1;
64 static gint ett_nlsp_lsp_info            = -1;
65 static gint ett_nlsp_lsp_clv_area_addr   = -1;
66 static gint ett_nlsp_lsp_clv_mgt_info    = -1;
67 static gint ett_nlsp_lsp_clv_link_info   = -1;
68 static gint ett_nlsp_lsp_clv_svcs_info   = -1;
69 static gint ett_nlsp_lsp_clv_ext_routes  = -1;
70 static gint ett_nlsp_lsp_clv_unknown     = -1;
71 static gint ett_nlsp_csnp_lsp_entries    = -1;
72 static gint ett_nlsp_csnp_lsp_entry      = -1;
73 static gint ett_nlsp_csnp_clv_unknown    = -1;
74 static gint ett_nlsp_psnp_lsp_entries    = -1;
75 static gint ett_nlsp_psnp_lsp_entry      = -1;
76 static gint ett_nlsp_psnp_clv_unknown    = -1;
77
78 #define PACKET_TYPE_MASK        0x1f
79
80 /*
81  * See
82  *
83  *      http://www.cisco.com/univercd/cc/td/doc/cisintwk/ito_doc/nlsp.htm
84  *
85  * for some information about Hello packets.
86  */
87
88 #define NLSP_TYPE_L1_HELLO      15
89 #define NLSP_TYPE_WAN_HELLO     17
90 #define NLSP_TYPE_L1_LSP        18
91 #define NLSP_TYPE_L1_CSNP       24
92 #define NLSP_TYPE_L1_PSNP       26
93
94 static const value_string nlsp_packet_type_vals[] = {
95         { NLSP_TYPE_L1_HELLO,  "L1 Hello"},
96         { NLSP_TYPE_WAN_HELLO, "WAN Hello"},
97         { NLSP_TYPE_L1_LSP,    "L1 LSP"},
98         { NLSP_TYPE_L1_CSNP,   "L1 CSNP"},
99         { NLSP_TYPE_L1_PSNP,   "L1 PSNP"},
100         { 0,                   NULL}
101 };
102
103 static const value_string nlsp_attached_flag_vals[] = {
104         { 0, "Other routing areas cannot be reached through this router"},
105         { 1, "Other routing areas can be reached through this router"},
106         { 0, NULL}
107 };
108
109 static const value_string nlsp_router_type_vals[] = {
110         { 1, "Level 1 Router"},
111         { 3, "Level 1 and Level 2 Router"},
112         { 0, NULL}
113 };
114
115 static const true_false_string supported_string = {
116         "Supported",
117         "Unsupported"
118 };
119
120 /*
121  * Our sub-packet dismantle structure for CLV's
122  */
123 typedef struct {
124         int     optcode;                /* code for option */
125         char    *tree_text;             /* text for fold out */
126         gint    *tree_id;               /* id for add_item */
127         void    (*dissect)(tvbuff_t *tvb, proto_tree *tree,
128                                 int offset, int length);
129 } nlsp_clv_handle_t;
130
131 /*
132  * Name: nlsp_dissect_unknown()
133  *
134  * Description:
135  *      There was some error in the protocol and we are in unknown space
136  *      here.  Add a tree item to cover the error and go on.  Note
137  *      that we make sure we don't go off the end of the bleedin packet here!
138  *
139  * Input
140  *      tvbuff_t * : tvbuffer for packet data
141  *      proto_tree * : tree of display data.  May be NULL.
142  *      int : current offset into packet data
143  *      char * : format text
144  *      subsequent args : arguments to format
145  *
146  * Output:
147  *      void (may modify proto tree)
148  */
149 void
150 nlsp_dissect_unknown(tvbuff_t *tvb, proto_tree *tree, int offset,
151         char *fmat, ...)
152 {
153         va_list ap;
154
155         va_start(ap, fmat);
156         proto_tree_add_text_valist(tree, tvb, offset, -1, fmat, ap);
157         va_end(ap);
158 }
159
160 /*
161  * Name: nlsp_dissect_clvs()
162  *
163  * Description:
164  *      Dispatch routine to shred all the CLVs in a packet.  We just
165  *      walk through the clv entries in the packet.  For each one, we
166  *      search the passed in valid clv's for this protocol (opts) for
167  *      a matching code.  If found, we add to the display tree and
168  *      then call the dissector.  If it is not, we just post an
169  *      "unknown" clv entry using the passed in unknown clv tree id.
170  *
171  * Input:
172  *      tvbuff_t * : tvbuffer for packet data
173  *      proto_tree * : protocol display tree to fill out.  May be NULL
174  *      int : offset into packet data where we are.
175  *      nlsp_clv_handle_t * : NULL dissector terminated array of codes
176  *              and handlers (along with tree text and tree id's).
177  *      int : length of CLV area.
178  *      int : unknown clv tree id
179  *
180  * Output:
181  *      void, but we will add to proto tree if !NULL.
182  */
183 static void
184 nlsp_dissect_clvs(tvbuff_t *tvb, proto_tree *tree, int offset,
185         const nlsp_clv_handle_t *opts, int len, int unknown_tree_id)
186 {
187         guint8 code;
188         guint8 length;
189         int q;
190         proto_item      *ti;
191         proto_tree      *clv_tree;
192         int             adj;
193
194         while ( len > 0 ) {
195                 code = tvb_get_guint8(tvb, offset);
196                 offset += 1;
197
198                 length = tvb_get_guint8(tvb, offset);
199                 offset += 1;
200
201                 adj = (sizeof(code) + sizeof(length) + length);
202                 len -= adj;
203                 if ( len < 0 ) {
204                         nlsp_dissect_unknown(tvb, tree, offset,
205                                 "Short CLV header (%d vs %d)",
206                                 adj, len + adj );
207                         return;
208                 }
209                 q = 0;
210                 while ((opts[q].dissect != NULL )&&( opts[q].optcode != code )){
211                         q++;
212                 }
213                 if ( opts[q].dissect ) {
214                         if (tree) {
215                                 /* adjust by 2 for code/len octets */
216                                 ti = proto_tree_add_text(tree, tvb, offset - 2,
217                                         length + 2, "%s (%u)",
218                                         opts[q].tree_text, length );
219                                 clv_tree = proto_item_add_subtree(ti,
220                                         *opts[q].tree_id );
221                         } else {
222                                 clv_tree = NULL;
223                         }
224                         opts[q].dissect(tvb, clv_tree, offset,
225                             length);
226                 } else {
227                         if (tree) {
228                                 ti = proto_tree_add_text(tree, tvb, offset - 2,
229                                         length + 2, "Unknown code %u (%u)",
230                                         code, length);
231                                 clv_tree = proto_item_add_subtree(ti,
232                                         unknown_tree_id );
233                         } else {
234                                 clv_tree = NULL;
235                         }
236                 }
237                 offset += length;
238         }
239 }
240
241 /*
242  * Name: dissect_area_address_clv()
243  *
244  * Description:
245  *      Decode an area address clv.
246  *
247  * Input:
248  *      tvbuff_t * : tvbuffer for packet data
249  *      proto_tree * : protocol display tree to fill out.  May be NULL
250  *      int : offset into packet data where we are.
251  *      int : length of clv we are decoding
252  *
253  * Output:
254  *      void, but we will add to proto tree if !NULL.
255  */
256 static void
257 dissect_area_address_clv(tvbuff_t *tvb, proto_tree *tree, int offset,
258     int length)
259 {
260         while (length > 0) {
261                 if (length < 4) {
262                         nlsp_dissect_unknown(tvb, tree, offset,
263                             "Short area address entry");
264                         return;
265                 }
266                 if (tree) {
267                         proto_tree_add_text(tree, tvb, offset, 4,
268                             "Area address network number: 0x%08x",
269                             tvb_get_ntohl(tvb, offset));
270                 }
271                 offset += 4;
272                 length -= 4;
273
274                 if (length < 4) {
275                         nlsp_dissect_unknown(tvb, tree, offset,
276                             "Short area address entry");
277                         return;
278                 }
279                 if (tree) {
280                         proto_tree_add_text(tree, tvb, offset, 4,
281                             "Area address mask: 0x%08x",
282                             tvb_get_ntohl(tvb, offset));
283                 }
284                 offset += 4;
285                 length -= 4;
286         }
287 }
288
289 /*
290  * Name: dissect_neighbor_clv()
291  *
292  * Description:
293  *      Decode an neighbor clv.
294  *
295  * Input:
296  *      tvbuff_t * : tvbuffer for packet data
297  *      proto_tree * : protocol display tree to fill out.  May be NULL
298  *      int : offset into packet data where we are.
299  *      int : length of clv we are decoding
300  *
301  * Output:
302  *      void, but we will add to proto tree if !NULL.
303  */
304 static void
305 dissect_neighbor_clv(tvbuff_t *tvb, proto_tree *tree, int offset,
306     int length)
307 {
308         while (length > 0) {
309                 if (length < 6) {
310                         nlsp_dissect_unknown(tvb, tree, offset,
311                             "Short neighbor entry");
312                         return;
313                 }
314                 if (tree) {
315                         proto_tree_add_text(tree, tvb, offset, 6,
316                             "Neighbor: %s",
317                             ether_to_str(tvb_get_ptr(tvb, offset, 6)));
318                 }
319                 offset += 6;
320                 length -= 6;
321         }
322 }
323
324 /*
325  * Name: dissect_hello_local_mtu_clv()
326  *
327  * Description:
328  *      Decode for a hello packet's local MTU clv.
329  *
330  * Input:
331  *      tvbuff_t * : tvbuffer for packet data
332  *      proto_tree * : protocol display tree to fill out.  May be NULL
333  *      int : offset into packet data where we are.
334  *      int : length of clv we are decoding
335  *
336  * Output:
337  *      void, but we will add to proto tree if !NULL.
338  */
339 static void
340 dissect_hello_local_mtu_clv(tvbuff_t *tvb, proto_tree *tree, int offset,
341     int length)
342 {
343         if (length < 4) {
344                 nlsp_dissect_unknown(tvb, tree, offset,
345                     "Short link info entry");
346                 return;
347         }
348         if (tree) {
349                 proto_tree_add_text(tree, tvb, offset, 4,
350                     "MTU Size: %u",
351                     tvb_get_ntohl(tvb, offset));
352         }
353         offset += 4;
354         length -= 4;
355 }
356
357 static const nlsp_clv_handle_t clv_hello_opts[] = {
358         {
359                 0xC0,
360                 "Area address(es)",
361                 &ett_nlsp_hello_clv_area_addr,
362                 dissect_area_address_clv
363         },
364         {
365                 6,
366                 "Neighbors",
367                 &ett_nlsp_hello_clv_neighbors,
368                 dissect_neighbor_clv
369         },
370         {
371                 0xC5,
372                 "Local MTU",
373                 &ett_nlsp_hello_local_mtu,
374                 dissect_hello_local_mtu_clv
375         },
376
377         {
378                 0,
379                 "",
380                 NULL,
381                 NULL
382         }
383 };
384
385 /*
386  * Name: nlsp_dissect_nlsp_hello()
387  *
388  * Description:
389  *      This procedure rips apart NLSP hellos.
390  *
391  * Input:
392  *      tvbuff_t * : tvbuffer for packet data
393  *      proto_tree * : protocol display tree to add to.  May be NULL.
394  *      int offset : our offset into packet data.
395  *      int : hello type, a la NLSP_TYPE_* values
396  *      int : header length of packet.
397  *
398  * Output:
399  *      void, will modify proto_tree if not NULL.
400  */
401 #define NLSP_HELLO_CTYPE_MASK           0x03
402 #define NLSP_HELLO_STATE_MASK           0xC0
403 #define NLSP_HELLO_MULTICAST_MASK       0x10
404
405 static const value_string nlsp_hello_state_vals[] = {
406         { 0, "Up" },
407         { 1, "Initializing" },
408         { 2, "Down" },
409         { 0, NULL }
410 };
411
412 #define NLSP_HELLO_TYPE_RESERVED        0
413 #define NLSP_HELLO_TYPE_LEVEL_1         1
414 #define NLSP_HELLO_TYPE_LEVEL_2         2
415 #define NLSP_HELLO_TYPE_LEVEL_12        3
416
417 static const value_string nlsp_hello_circuit_type_vals[] = {
418         { NLSP_HELLO_TYPE_RESERVED,     "Reserved 0 (discard PDU)"},
419         { NLSP_HELLO_TYPE_LEVEL_1,      "Level 1 only"},
420         { NLSP_HELLO_TYPE_LEVEL_2,      "Level 2 only"},
421         { NLSP_HELLO_TYPE_LEVEL_12,     "Level 1 and 2"},
422         { 0,            NULL}
423 };
424
425 #define NLSP_HELLO_PRIORITY_MASK        0x7f
426
427 static void
428 nlsp_dissect_nlsp_hello(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
429     int offset, int hello_type, int header_length)
430 {
431         guint16         packet_length;
432         int             len;
433         guint16         holding_timer;
434
435         if (tree) {
436                 if (hello_type == NLSP_TYPE_WAN_HELLO) {
437                         proto_tree_add_item(tree, hf_nlsp_hello_state, tvb,
438                             offset, 1, FALSE);
439                 } else {
440                         proto_tree_add_item(tree, hf_nlsp_hello_multicast, tvb,
441                             offset, 1, FALSE);
442                 }
443                 proto_tree_add_item(tree, hf_nlsp_hello_circuit_type, tvb,
444                     offset, 1, FALSE);
445         }
446         offset += 1;
447
448         if (tree) {
449                 proto_tree_add_text(tree, tvb, offset, 6,
450                     "Sending Router System ID: %s",
451                     ether_to_str(tvb_get_ptr(tvb, offset, 6)));
452         }
453         if (check_col(pinfo->cinfo, COL_INFO)) {
454                 col_append_fstr(pinfo->cinfo, COL_INFO, ", System ID: %s",
455                     ether_to_str(tvb_get_ptr(tvb, offset, 6)));
456         }
457         offset += 6;
458
459         if (tree) {
460                 holding_timer = tvb_get_ntohs(tvb, offset);
461                 proto_tree_add_uint_format(tree, hf_nlsp_hello_holding_timer,
462                     tvb, offset, 2, holding_timer,
463                     "Holding Timer: %us", holding_timer);
464         }
465         offset += 2;
466
467         packet_length = tvb_get_ntohs(tvb, offset);
468         if (tree) {
469                 proto_tree_add_uint(tree, hf_nlsp_packet_length, tvb,
470                         offset, 2, packet_length);
471         }
472         offset += 2;
473
474         if (tree) {
475                 proto_tree_add_item(tree, hf_nlsp_hello_priority, tvb,
476                     offset, 1, FALSE);
477         }
478         offset += 1;
479
480         if (hello_type == NLSP_TYPE_WAN_HELLO) {
481                 if (tree) {
482                         proto_tree_add_text(tree, tvb, offset, 1,
483                             "Local WAN Circuit ID: %u",
484                             tvb_get_guint8(tvb, offset));
485                 }
486                 offset += 1;
487         } else {
488                 if (tree) {
489                         proto_tree_add_text(tree, tvb, offset, 6,
490                             "Designated Router System ID: %s",
491                             ether_to_str(tvb_get_ptr(tvb, offset, 6)));
492                         proto_tree_add_text(tree, tvb, offset+6, 1,
493                             "Designated Router Pseudonode ID: %u",
494                             tvb_get_guint8(tvb, offset+6));
495                 }
496                 offset += 7;
497         }
498
499         len = packet_length - header_length;
500         if (len < 0) {
501                 nlsp_dissect_unknown(tvb, tree, offset,
502                         "packet header length %d went beyond packet",
503                         header_length);
504                 return;
505         }
506
507         /*
508          * Now, we need to decode our CLVs.  We need to pass in
509          * our list of valid ones!
510          */
511         nlsp_dissect_clvs(tvb, tree, offset,
512             clv_hello_opts, len, ett_nlsp_hello_clv_unknown);
513 }
514
515 /*
516  * Name: dissect_lsp_mgt_info_clv()
517  *
518  * Description:
519  *      Decode for a lsp packet's management information clv.
520  *
521  * Input:
522  *      tvbuff_t * : tvbuffer for packet data
523  *      proto_tree * : protocol display tree to fill out.  May be NULL
524  *      int : offset into packet data where we are.
525  *      int : length of clv we are decoding
526  *
527  * Output:
528  *      void, but we will add to proto tree if !NULL.
529  */
530 static void
531 dissect_lsp_mgt_info_clv(tvbuff_t *tvb, proto_tree *tree, int offset,
532     int length)
533 {
534         guint8 name_length;
535
536         if (length < 4) {
537                 nlsp_dissect_unknown(tvb, tree, offset,
538                     "Short management info entry");
539                 return;
540         }
541         if (tree) {
542                 proto_tree_add_text(tree, tvb, offset, 4,
543                     "Network number: 0x%08x",
544                     tvb_get_ntohl(tvb, offset));
545         }
546         offset += 4;
547         length -= 4;
548
549         if (length < 6) {
550                 nlsp_dissect_unknown(tvb, tree, offset,
551                     "Short management info entry");
552                 return;
553         }
554         if (tree) {
555                 proto_tree_add_text(tree, tvb, offset, 6,
556                     "Node number: %s",
557                     ether_to_str(tvb_get_ptr(tvb, offset, 6)));
558         }
559         offset += 6;
560         length -= 6;
561
562         if (length < 1) {
563                 nlsp_dissect_unknown(tvb, tree, offset,
564                     "Short management info entry");
565                 return;
566         }
567         if (tree) {
568                 proto_tree_add_text(tree, tvb, offset, 1,
569                     "IPX version number: %u",
570                     tvb_get_guint8(tvb, offset));
571         }
572         offset += 1;
573         length -= 1;
574
575         if (length < 1) {
576                 nlsp_dissect_unknown(tvb, tree, offset,
577                     "Short management info entry");
578                 return;
579         }
580         name_length = tvb_get_guint8(tvb, offset);
581         if (tree) {
582                 proto_tree_add_text(tree, tvb, offset, 1,
583                     "Name length: %u", name_length);
584         }
585         offset += 1;
586         length -= 1;
587
588         if (name_length != 0) {
589                 if (length < name_length) {
590                         nlsp_dissect_unknown(tvb, tree, offset,
591                             "Short management info entry");
592                         return;
593                 }
594                 if (tree) {
595                         proto_tree_add_text(tree, tvb, offset, name_length,
596                             "Name: %s",
597                             tvb_format_text(tvb, offset, name_length));
598                 }
599                 offset += name_length;
600                 length -= name_length;
601         }
602 }
603
604 /*
605  * Name: dissect_lsp_link_info_clv()
606  *
607  * Description:
608  *      Decode for a lsp packet's link information clv.
609  *
610  * Input:
611  *      tvbuff_t * : tvbuffer for packet data
612  *      proto_tree * : protocol display tree to fill out.  May be NULL
613  *      int : offset into packet data where we are.
614  *      int : length of clv we are decoding
615  *
616  * Output:
617  *      void, but we will add to proto tree if !NULL.
618  */
619 static const value_string media_type_vals[] = {
620         { 0x0000, "Generic LAN" },
621         { 0x8000, "Generic WAN" },
622         { 0x0001, "Localtalk" },
623         { 0x0002, "Ethernet II" },
624         { 0x0003, "IEEE 802.3 with IEEE 802.2 without SNAP" },
625         { 0x0005, "IEEE 802.3 with IPX header and no 802.2 header" },
626         { 0x000A, "IEEE 802.3 with IEEE 802.2 and SNAP" },
627         { 0x0004, "IEEE 802.5 with IEEE 802.2 without SNAP" },
628         { 0x000B, "IEEE 802.5 with IEEE 802.2 and SNAP" },
629         { 0x0006, "IEEE 802.4" },
630         { 0x0007, "IBM PC Network II" },
631         { 0x0008, "Gateway G/Net" },
632         { 0x0009, "Proteon ProNET" },
633         { 0x000C, "Racore LANPAC" },
634         { 0x800D, "ISDN" },
635         { 0x000E, "ARCnet" },
636         { 0x000F, "IBM PC Network II with 802.2 without SNAP" },
637         { 0x0010, "IBM PC Network II with 802.2 and SNAP" },
638         { 0x0011, "Corvus OmniNet at 4 Mbps" },
639         { 0x0012, "Harris Adacom" },
640         { 0x0013, "IP tunnel" },
641         { 0x8013, "IP Relay" },
642         { 0x0014, "FDDI with 802.2 without SNAP" },
643         { 0x0015, "Commtex IVDLAN" },
644         { 0x0016, "Dataco OSI" },
645         { 0x0017, "FDDI with 802.2 and SNAP" },
646         { 0x0018, "IBM SDLC tunnel" },
647         { 0x0019, "PC Office frame" },
648         { 0x001A, "Hypercommunications WAIDNET" },
649         { 0x801C, "PPP" },
650         { 0x801D, "Proxim RangeLAN" },
651         { 0x801E, "X.25" },
652         { 0x801F, "Frame Relay" },
653         { 0x0020, "Integrated Workstations BUS-NET" },
654         { 0x8021, "Novell SNA Links" },
655         { 0,      NULL }
656 };
657
658 static void
659 dissect_lsp_link_info_clv(tvbuff_t *tvb, proto_tree *tree, int offset,
660     int length)
661 {
662         guint8 flags_cost;
663
664         if (length < 1) {
665                 nlsp_dissect_unknown(tvb, tree, offset,
666                     "Short link info entry");
667                 return;
668         }
669         if (tree) {
670                 flags_cost = tvb_get_guint8(tvb, offset);
671                 proto_tree_add_text(tree, tvb, offset, 1,
672                     decode_boolean_bitfield(flags_cost, 0x80, 1*8,
673                         "Cost not present", "Cost present"));
674                 if (!(flags_cost & 0x80)) {
675                         /*
676                          * 0x80 clear => cost present.
677                          */
678                         proto_tree_add_text(tree, tvb, offset, 1,
679                             decode_boolean_bitfield(flags_cost, 0x40, 1*8,
680                                 "Cost is internal metric",
681                                 "Cost is external metric"));
682                         proto_tree_add_text(tree, tvb, offset, 1,
683                             decode_numeric_bitfield(flags_cost, 0x3F, 1*8,
684                                 "Cost = %u"));
685                 }
686         }
687         offset += 1;
688         length -= 1;
689
690         if (length < 3) {
691                 nlsp_dissect_unknown(tvb, tree, offset,
692                     "Short link info entry");
693                 return;
694         }
695         offset += 3;    /* Reserved */
696         length -= 3;
697
698         if (length < 7) {
699                 nlsp_dissect_unknown(tvb, tree, offset,
700                     "Short link info entry");
701                 return;
702         }
703         if (tree) {
704                 proto_tree_add_text(tree, tvb, offset, 6,
705                     "Router System ID: %s",
706                     ether_to_str(tvb_get_ptr(tvb, offset, 6)));
707                 proto_tree_add_text(tree, tvb, offset+6, 1,
708                     "Router Pseudonode ID: %u",
709                     tvb_get_guint8(tvb, offset+6));
710         }
711         offset += 7;
712         length -= 7;
713
714         if (length < 4) {
715                 nlsp_dissect_unknown(tvb, tree, offset,
716                     "Short link info entry");
717                 return;
718         }
719         if (tree) {
720                 proto_tree_add_text(tree, tvb, offset, 4,
721                     "MTU Size: %u",
722                     tvb_get_ntohl(tvb, offset));
723         }
724         offset += 4;
725         length -= 4;
726
727         if (length < 4) {
728                 nlsp_dissect_unknown(tvb, tree, offset,
729                     "Short link info entry");
730                 return;
731         }
732         if (tree) {
733                 proto_tree_add_text(tree, tvb, offset, 4,
734                     "Delay: %uus",
735                     tvb_get_ntohl(tvb, offset));
736         }
737         offset += 4;
738         length -= 4;
739
740         if (length < 4) {
741                 nlsp_dissect_unknown(tvb, tree, offset,
742                     "Short link info entry");
743                 return;
744         }
745         if (tree) {
746                 proto_tree_add_text(tree, tvb, offset, 4,
747                     "Throughput: %u bits/s",
748                     tvb_get_ntohl(tvb, offset));
749         }
750         offset += 4;
751         length -= 4;
752
753         if (length < 2) {
754                 nlsp_dissect_unknown(tvb, tree, offset,
755                     "Short link info entry");
756                 return;
757         }
758         if (tree) {
759                 proto_tree_add_text(tree, tvb, offset, 2,
760                     "Media type: %s",
761                     val_to_str(tvb_get_ntohs(tvb, offset), media_type_vals,
762                         "Unknown (0x%04x)"));
763         }
764         offset += 2;
765         length -= 2;
766 }
767
768 /*
769  * Name: dissect_lsp_svcs_info_clv()
770  *
771  * Description:
772  *      Decode for a lsp packet's services information clv.
773  *
774  * Input:
775  *      tvbuff_t * : tvbuffer for packet data
776  *      proto_tree * : protocol display tree to fill out.  May be NULL
777  *      int : offset into packet data where we are.
778  *      int : length of clv we are decoding
779  *
780  * Output:
781  *      void, but we will add to proto tree if !NULL.
782  */
783 static void
784 dissect_lsp_svcs_info_clv(tvbuff_t *tvb, proto_tree *tree, int offset,
785     int length)
786 {
787         if (length < 1) {
788                 nlsp_dissect_unknown(tvb, tree, offset,
789                     "Short services info entry");
790                 return;
791         }
792         if (tree) {
793                 proto_tree_add_text(tree, tvb, offset, 1,
794                     "Hops to reach the service: %u",
795                     tvb_get_guint8(tvb, offset));
796         }
797         offset += 1;
798         length -= 1;
799
800         if (length < 4) {
801                 nlsp_dissect_unknown(tvb, tree, offset,
802                     "Short services info entry");
803                 return;
804         }
805         if (tree) {
806                 proto_tree_add_text(tree, tvb, offset, 4,
807                     "Network number: 0x%08x",
808                     tvb_get_ntohl(tvb, offset));
809         }
810         offset += 4;
811         length -= 4;
812
813         if (length < 6) {
814                 nlsp_dissect_unknown(tvb, tree, offset,
815                     "Short services info entry");
816                 return;
817         }
818         if (tree) {
819                 proto_tree_add_text(tree, tvb, offset, 6,
820                     "Node number: %s",
821                     ether_to_str(tvb_get_ptr(tvb, offset, 6)));
822         }
823         offset += 6;
824         length -= 6;
825
826         if (length < 2) {
827                 nlsp_dissect_unknown(tvb, tree, offset,
828                     "Short services info entry");
829                 return;
830         }
831         if (tree) {
832                 proto_tree_add_text(tree, tvb, offset, 2,
833                     "Socket: %s",
834                     val_to_str(tvb_get_ntohs(tvb, offset), ipx_socket_vals,
835                         "Unknown (0x%04x)"));
836         }
837         offset += 2;
838         length -= 2;
839
840         if (length < 2) {
841                 nlsp_dissect_unknown(tvb, tree, offset,
842                     "Short services info entry");
843                 return;
844         }
845         if (tree) {
846                 proto_tree_add_text(tree, tvb, offset, 2,
847                     "Type: %s",
848                     val_to_str(tvb_get_ntohs(tvb, offset), server_vals,
849                         "Unknown (0x%04x)"));
850         }
851         offset += 2;
852         length -= 2;
853
854         if (length > 0) {
855                 if (tree) {
856                         proto_tree_add_text(tree, tvb, offset, length,
857                             "Service Name: %s",
858                             tvb_format_text(tvb, offset, length));
859                 }
860         }
861 }
862
863
864 /*
865  * Name: dissect_lsp_ext_routes_clv()
866  *
867  * Description:
868  *      Decode for a lsp packet's external routes clv.
869  *
870  * Input:
871  *      tvbuff_t * : tvbuffer for packet data
872  *      proto_tree * : protocol display tree to fill out.  May be NULL
873  *      int : offset into packet data where we are.
874  *      int : length of clv we are decoding
875  *
876  * Output:
877  *      void, but we will add to proto tree if !NULL.
878  */
879 static void
880 dissect_lsp_ext_routes_clv(tvbuff_t *tvb, proto_tree *tree, int offset,
881     int length)
882 {
883         while (length > 0) {
884                 if (length < 1) {
885                         nlsp_dissect_unknown(tvb, tree, offset,
886                             "Short external routes entry");
887                         return;
888                 }
889                 if (tree) {
890                         proto_tree_add_text(tree, tvb, offset, 1,
891                             "Hops: %u",
892                             tvb_get_guint8(tvb, offset));
893                 }
894                 offset += 1;
895                 length -= 1;
896
897                 if (length < 4) {
898                         nlsp_dissect_unknown(tvb, tree, offset,
899                             "Short external routes entry");
900                         return;
901                 }
902                 if (tree) {
903                         proto_tree_add_text(tree, tvb, offset, 4,
904                             "Network number: 0x%08x",
905                             tvb_get_ntohl(tvb, offset));
906                 }
907                 offset += 4;
908                 length -= 4;
909
910                 if (length < 2) {
911                         nlsp_dissect_unknown(tvb, tree, offset,
912                             "Short external routes entry");
913                         return;
914                 }
915                 if (tree) {
916                         proto_tree_add_text(tree, tvb, offset, 2,
917                             "RIP delay: %u ticks",
918                             tvb_get_ntohs(tvb, offset));
919                 }
920                 offset += 2;
921                 length -= 2;
922         }
923 }
924
925 static const nlsp_clv_handle_t clv_l1_lsp_opts[] = {
926         {
927                 0xC0,
928                 "Area address(es)",
929                 &ett_nlsp_lsp_clv_area_addr,
930                 dissect_area_address_clv
931         },
932         {
933                 0xC1,
934                 "Management information",
935                 &ett_nlsp_lsp_clv_mgt_info,
936                 dissect_lsp_mgt_info_clv
937         },
938         {
939                 0xC2,
940                 "Link information",
941                 &ett_nlsp_lsp_clv_link_info,
942                 dissect_lsp_link_info_clv
943         },
944         {
945                 0xC3,
946                 "Services information",
947                 &ett_nlsp_lsp_clv_svcs_info,
948                 dissect_lsp_svcs_info_clv
949         },
950         {
951                 0xC4,
952                 "External routes",
953                 &ett_nlsp_lsp_clv_ext_routes,
954                 dissect_lsp_ext_routes_clv
955         },
956
957         {
958                 0,
959                 "",
960                 NULL,
961                 NULL
962         }
963 };
964
965 /*
966  * Name: nlsp_dissect_nlsp_lsp()
967  *
968  * Description:
969  *      Print out the LSP part of the main header and then call the CLV
970  *      de-mangler with the right list of valid CLVs.
971  *
972  * Input:
973  *      tvbuff_t * : tvbuffer for packet data
974  *      proto_tree * : protocol display tree to add to.  May be NULL.
975  *      int offset : our offset into packet data.
976  *      int : header length of packet.
977  *
978  * Output:
979  *      void, but we will add to proto tree if !NULL.
980  */
981 /* P | ATT | OVERFLOW | ROUTER TYPE FIELD description */
982 #define NLSP_LSP_PARTITION_MASK     0x80
983 #define NLSP_LSP_PARTITION_SHIFT    7
984 #define NLSP_LSP_PARTITION(info)    (((info) & NLSP_LSP_PARTITION_MASK) >> NLSP_LSP_PARTITION_SHIFT)
985
986 #define NLSP_LSP_ATT_MASK     0x78
987 #define NLSP_LSP_ATT_SHIFT    3
988 #define NLSP_LSP_ATT(info)    (((info) & NLSP_LSP_ATT_MASK) >> NLSP_LSP_ATT_SHIFT)
989
990 #define NLSP_LSP_OVERFLOW_MASK     0x04
991 #define NLSP_LSP_OVERFLOW_SHIFT    2
992 #define NLSP_LSP_OVERFLOW(info)    (((info) & NLSP_LSP_OVERFLOW_MASK) >> NLSP_LSP_OVERFLOW_SHIFT)
993
994 #define NLSP_LSP_ROUTER_TYPE_MASK     0x03
995 #define NLSP_LSP_ROUTER_TYPE(info)    ((info) & NLSP_LSP_ROUTER_TYPE_MASK)
996
997 static void
998 nlsp_dissect_nlsp_lsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
999     int offset, int header_length)
1000 {
1001         guint16         packet_length;
1002         guint16         remaining_lifetime;
1003         guint32         sequence_number;
1004         int             len;
1005
1006         packet_length = tvb_get_ntohs(tvb, offset);
1007         if (tree) {
1008                 proto_tree_add_uint(tree, hf_nlsp_packet_length, tvb,
1009                         offset, 2, packet_length);
1010         }
1011         offset += 2;
1012
1013         remaining_lifetime = tvb_get_ntohs(tvb, offset);
1014         if (tree) {
1015                 proto_tree_add_text(tree, tvb, offset, 2,
1016                                     "Remaining Lifetime: %us",
1017                                     remaining_lifetime);
1018         }
1019         offset += 2;
1020
1021         if (check_col(pinfo->cinfo, COL_INFO)) {
1022                 col_append_fstr(pinfo->cinfo, COL_INFO, ", LSP ID: %s",
1023                     ether_to_str(tvb_get_ptr(tvb, offset, 6)));
1024         }
1025         if (tree) {
1026                 proto_tree_add_text(tree, tvb, offset, 6,
1027                     "LSP ID system ID: %s",
1028                     ether_to_str(tvb_get_ptr(tvb, offset, 6)));
1029         }
1030         offset += 6;
1031         /* XXX - append the pseudonode ID */
1032         if (tree) {
1033                 proto_tree_add_text(tree, tvb, offset, 1,
1034                     "LSP ID pseudonode ID: %u",
1035                     tvb_get_guint8(tvb, offset));
1036         }
1037         offset += 1;
1038         if (tree) {
1039                 proto_tree_add_text(tree, tvb, offset, 1,
1040                     "LSP ID LSP number: %u",
1041                     tvb_get_guint8(tvb, offset));
1042         }
1043         offset += 1;
1044
1045         sequence_number = tvb_get_ntohl(tvb, offset);
1046         if (check_col(pinfo->cinfo, COL_INFO)) {
1047                 col_append_fstr(pinfo->cinfo, COL_INFO,
1048                     ", Sequence: 0x%08x, Lifetime: %us",
1049                     sequence_number, remaining_lifetime);
1050         }
1051         if (tree) {
1052                 proto_tree_add_uint(tree, hf_nlsp_lsp_sequence_number, tvb,
1053                         offset, 4, sequence_number);
1054         }
1055         offset += 4;
1056
1057         if (tree) {
1058                 /* XXX -> we could validate the cksum here! */
1059                 proto_tree_add_item(tree, hf_nlsp_lsp_checksum, tvb,
1060                         offset, 2, FALSE );
1061         }
1062         offset += 2;
1063
1064         if (tree) {
1065                 proto_tree_add_item(tree, hf_nlsp_lsp_p, tvb,
1066                     offset, 1, FALSE);
1067                 proto_tree_add_item(tree, hf_nlsp_lsp_attached_flag, tvb,
1068                     offset, 1, FALSE);
1069                 proto_tree_add_item(tree, hf_nlsp_lsp_lspdbol, tvb,
1070                     offset, 1, FALSE);
1071                 proto_tree_add_item(tree, hf_nlsp_lsp_router_type, tvb,
1072                     offset, 1, FALSE);
1073         }
1074         offset += 1;
1075
1076         len = packet_length - header_length;
1077         if (len < 0) {
1078                 nlsp_dissect_unknown(tvb, tree, offset,
1079                         "packet header length %d went beyond packet",
1080                          header_length);
1081                 return;
1082         }
1083
1084         /*
1085          * Now, we need to decode our CLVs.  We need to pass in
1086          * our list of valid ones!
1087          */
1088         nlsp_dissect_clvs(tvb, tree, offset,
1089                 clv_l1_lsp_opts, len, ett_nlsp_lsp_clv_unknown);
1090 }
1091
1092 /*
1093  * Name: dissect_snp_lsp_entries()
1094  *
1095  * Description:
1096  *      All the snp packets use a common payload format.  We have up
1097  *      to n entries (based on length), which are made of:
1098  *              2 : remaining life time
1099  *              8 : lsp id
1100  *              4 : sequence number
1101  *              2 : checksum
1102  *
1103  * Input:
1104  *      tvbuff_t * : tvbuffer for packet data
1105  *      proto_tree * : protocol display tree to fill out.  May be NULL
1106  *      int : offset into packet data where we are.
1107  *      int : length of payload to decode.
1108  *
1109  * Output:
1110  *      void, but we will add to proto tree if !NULL.
1111  */
1112 static void
1113 dissect_csnp_lsp_entries(tvbuff_t *tvb, proto_tree *tree, int offset,
1114     int length)
1115 {
1116         proto_tree *subtree,*ti;
1117
1118         while (length > 0) {
1119                 if (length < 16) {
1120                         nlsp_dissect_unknown(tvb, tree, offset,
1121                             "Short CSNP header entry");
1122                         return;
1123                 }
1124
1125                 ti = proto_tree_add_text(tree, tvb, offset, 16,
1126                     "LSP-ID: %s, Sequence: 0x%08x, Lifetime: %5us, Checksum: 0x%04x",
1127                     ether_to_str(tvb_get_ptr(tvb, offset+2, 6)), /* XXX - rest of system ID */
1128                     tvb_get_ntohl(tvb, offset+10),
1129                     tvb_get_ntohs(tvb, offset),
1130                     tvb_get_ntohs(tvb, offset+14));
1131
1132                 subtree = proto_item_add_subtree(ti, ett_nlsp_csnp_lsp_entry);
1133
1134                 proto_tree_add_text(subtree, tvb, offset+2, 6,
1135                     "LSP ID source ID: %s",
1136                     ether_to_str(tvb_get_ptr(tvb, offset+2, 6)));
1137                 proto_tree_add_text(subtree, tvb, offset+8, 1,
1138                     "LSP ID pseudonode ID: %u",
1139                     tvb_get_guint8(tvb, offset+8));
1140                 proto_tree_add_text(subtree, tvb, offset+9, 1,
1141                     "LSP ID LSP number: %u",
1142                     tvb_get_guint8(tvb, offset+9));
1143
1144                 proto_tree_add_text(subtree, tvb, offset+10, 4,
1145                         "LSP Sequence Number: 0x%08x",
1146                         tvb_get_ntohl(tvb, offset+10));
1147
1148                 proto_tree_add_text(subtree, tvb, offset, 2,
1149                         "Remaining Lifetime: %us",
1150                         tvb_get_ntohs(tvb, offset));
1151
1152                 proto_tree_add_text(subtree, tvb, offset+14, 2,
1153                         "LSP checksum: 0x%04x",
1154                         tvb_get_ntohs(tvb, offset+14));
1155
1156                 length -= 16;
1157                 offset += 16;
1158         }
1159 }
1160
1161 static void
1162 dissect_psnp_lsp_entries(tvbuff_t *tvb, proto_tree *tree, int offset,
1163     int length)
1164 {
1165         proto_tree *subtree,*ti;
1166
1167         while (length > 0) {
1168                 if (length < 16) {
1169                         nlsp_dissect_unknown(tvb, tree, offset,
1170                             "Short PSNP header entry");
1171                         return;
1172                 }
1173
1174                 ti = proto_tree_add_text(tree, tvb, offset, 16,
1175                     "LSP-ID: %s, Sequence: 0x%08x, Lifetime: %5us, Checksum: 0x%04x",
1176                     ether_to_str(tvb_get_ptr(tvb, offset+2, 6)), /* XXX - rest of system ID */
1177                     tvb_get_ntohl(tvb, offset+10),
1178                     tvb_get_ntohs(tvb, offset),
1179                     tvb_get_ntohs(tvb, offset+14));
1180
1181                 subtree = proto_item_add_subtree(ti, ett_nlsp_psnp_lsp_entry);
1182
1183                 proto_tree_add_text(subtree, tvb, offset+2, 6,
1184                     "LSP ID source ID: %s",
1185                     ether_to_str(tvb_get_ptr(tvb, offset+2, 6)));
1186                 proto_tree_add_text(subtree, tvb, offset+8, 1,
1187                     "LSP ID pseudonode ID: %u",
1188                     tvb_get_guint8(tvb, offset+8));
1189                 proto_tree_add_text(subtree, tvb, offset+9, 1,
1190                     "LSP ID LSP number: %u",
1191                     tvb_get_guint8(tvb, offset+9));
1192
1193                 proto_tree_add_text(subtree, tvb, offset+10, 4,
1194                         "LSP Sequence Number: 0x%08x",
1195                         tvb_get_ntohl(tvb, offset+10));
1196
1197                 proto_tree_add_text(subtree, tvb, offset, 2,
1198                         "Remaining Lifetime: %us",
1199                         tvb_get_ntohs(tvb, offset));
1200
1201                 proto_tree_add_text(subtree, tvb, offset+14, 2,
1202                         "LSP checksum: 0x%04x",
1203                         tvb_get_ntohs(tvb, offset+14));
1204
1205                 length -= 16;
1206                 offset += 16;
1207         }
1208 }
1209
1210 static const nlsp_clv_handle_t clv_l1_csnp_opts[] = {
1211         {
1212                 9,
1213                 "LSP entries",
1214                 &ett_nlsp_csnp_lsp_entries,
1215                 dissect_csnp_lsp_entries
1216         },
1217
1218         {
1219                 0,
1220                 "",
1221                 NULL,
1222                 NULL
1223         }
1224 };
1225
1226 /*
1227  * Name: nlsp_dissect_nlsp_csnp()
1228  *
1229  * Description:
1230  *      Tear apart a L1 CSNP header and then call into payload dissect
1231  *      to pull apart the lsp id payload.
1232  *
1233  * Input:
1234  *      tvbuff_t * : tvbuffer for packet data
1235  *      proto_tree * : protocol display tree to add to.  May be NULL.
1236  *      int offset : our offset into packet data.
1237  *      int : header length of packet.
1238  *
1239  * Output:
1240  *      void, but we will add to proto tree if !NULL.
1241  */
1242 static void
1243 nlsp_dissect_nlsp_csnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1244     int offset, int header_length)
1245 {
1246         guint16         packet_length;
1247         int             len;
1248
1249         packet_length = tvb_get_ntohs(tvb, offset);
1250         if (tree) {
1251                 proto_tree_add_uint(tree, hf_nlsp_packet_length, tvb,
1252                         offset, 2, packet_length);
1253         }
1254         offset += 2;
1255
1256         if (check_col(pinfo->cinfo, COL_INFO)) {
1257                 col_append_fstr(pinfo->cinfo, COL_INFO, ", Source ID: %s",
1258                     ether_to_str(tvb_get_ptr(tvb, offset, 6)));
1259         }
1260         if (tree) {
1261                 proto_tree_add_text(tree, tvb, offset, 6,
1262                     "Source ID system ID: %s",
1263                     ether_to_str(tvb_get_ptr(tvb, offset, 6)));
1264         }
1265         offset += 6;
1266         /* XXX - add the pseudonode ID */
1267         if (tree) {
1268                 proto_tree_add_text(tree, tvb, offset, 1,
1269                     "Source ID pseudonode ID: %u",
1270                     tvb_get_guint8(tvb, offset));
1271         }
1272         offset += 1;
1273
1274         if (check_col(pinfo->cinfo, COL_INFO)) {
1275                 col_append_fstr(pinfo->cinfo, COL_INFO, ", Start LSP ID: %s",
1276                     ether_to_str(tvb_get_ptr(tvb, offset, 6)));
1277         }
1278         if (tree) {
1279                 proto_tree_add_text(tree, tvb, offset, 6,
1280                     "Start LSP ID source ID: %s",
1281                     ether_to_str(tvb_get_ptr(tvb, offset, 6)));
1282         }
1283         offset += 6;
1284         /* XXX - append the pseudonode ID */
1285         if (tree) {
1286                 proto_tree_add_text(tree, tvb, offset, 1,
1287                     "Start LSP ID pseudonode ID: %u",
1288                     tvb_get_guint8(tvb, offset));
1289         }
1290         offset += 1;
1291         if (tree) {
1292                 proto_tree_add_text(tree, tvb, offset, 1,
1293                     "Start LSP ID LSP number: %u",
1294                     tvb_get_guint8(tvb, offset));
1295         }
1296         offset += 1;
1297
1298         if (check_col(pinfo->cinfo, COL_INFO)) {
1299                 col_append_fstr(pinfo->cinfo, COL_INFO, ", End LSP ID: %s",
1300                     ether_to_str(tvb_get_ptr(tvb, offset, 6)));
1301         }
1302         if (tree) {
1303                 proto_tree_add_text(tree, tvb, offset, 6,
1304                     "End LSP ID source ID: %s",
1305                     ether_to_str(tvb_get_ptr(tvb, offset, 6)));
1306         }
1307         offset += 6;
1308         /* XXX - append the pseudonode ID */
1309         if (tree) {
1310                 proto_tree_add_text(tree, tvb, offset, 1,
1311                     "End LSP ID pseudonode ID: %u",
1312                     tvb_get_guint8(tvb, offset));
1313         }
1314         offset += 1;
1315         if (tree) {
1316                 proto_tree_add_text(tree, tvb, offset, 1,
1317                     "End LSP ID LSP number: %u",
1318                     tvb_get_guint8(tvb, offset));
1319         }
1320         offset += 1;
1321
1322         len = packet_length - header_length;
1323         if (len < 0) {
1324                 return;
1325         }
1326         /* Call into payload dissector */
1327         nlsp_dissect_clvs(tvb, tree, offset,
1328             clv_l1_csnp_opts, len, ett_nlsp_csnp_clv_unknown);
1329 }
1330
1331 static const nlsp_clv_handle_t clv_l1_psnp_opts[] = {
1332         {
1333                 9,
1334                 "LSP entries",
1335                 &ett_nlsp_psnp_lsp_entries,
1336                 dissect_psnp_lsp_entries
1337         },
1338
1339         {
1340                 0,
1341                 "",
1342                 NULL,
1343                 NULL
1344         }
1345 };
1346
1347 /*
1348  * Name: nlsp_dissect_nlsp_psnp()
1349  *
1350  * Description:
1351  *      Tear apart a L1 PSNP header and then call into payload dissect
1352  *      to pull apart the lsp id payload.
1353  *
1354  * Input:
1355  *      tvbuff_t * : tvbuffer for packet data
1356  *      proto_tree * : protocol display tree to add to.  May be NULL.
1357  *      int offset : our offset into packet data.
1358  *      int : header length of packet.
1359  *
1360  * Output:
1361  *      void, but we will add to proto tree if !NULL.
1362  */
1363 static void
1364 nlsp_dissect_nlsp_psnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
1365     int offset, int header_length)
1366 {
1367         guint16         packet_length;
1368         int             len;
1369
1370         packet_length = tvb_get_ntohs(tvb, offset);
1371         if (tree) {
1372                 proto_tree_add_uint(tree, hf_nlsp_packet_length, tvb,
1373                         offset, 2, packet_length);
1374         }
1375         offset += 2;
1376
1377         if (check_col(pinfo->cinfo, COL_INFO)) {
1378                 col_append_fstr(pinfo->cinfo, COL_INFO, ", Source ID: %s",
1379                     ether_to_str(tvb_get_ptr(tvb, offset, 6)));
1380         }
1381         if (tree) {
1382                 proto_tree_add_text(tree, tvb, offset, 6,
1383                     "Source ID system ID: %s",
1384                     ether_to_str(tvb_get_ptr(tvb, offset, 6)));
1385         }
1386         offset += 6;
1387         /* XXX - add the pseudonode ID */
1388         if (tree) {
1389                 proto_tree_add_text(tree, tvb, offset, 1,
1390                     "Source ID pseudonode ID: %u",
1391                     tvb_get_guint8(tvb, offset));
1392         }
1393         offset += 1;
1394
1395         len = packet_length - header_length;
1396         if (len < 0) {
1397                 return;
1398         }
1399         /* Call into payload dissector */
1400         nlsp_dissect_clvs(tvb, tree, offset,
1401             clv_l1_psnp_opts, len, ett_nlsp_psnp_clv_unknown);
1402 }
1403
1404 /*
1405  * Name: dissect_nlsp()
1406  *
1407  * Description:
1408  *      Main entry area for nlsp de-mangling.  This will build the
1409  *      main nlsp tree data and call the sub-protocols as needed.
1410  *
1411  * Input:
1412  *      tvbuff_t * : tvbuffer for packet data
1413  *      packet_info * : info for current packet
1414  *      proto_tree * : tree of display data.  May be NULL.
1415  *
1416  * Output:
1417  *      void, but we will add to the proto_tree if it is not NULL.
1418  */
1419 static void
1420 dissect_nlsp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1421 {
1422         proto_item *ti;
1423         proto_tree *nlsp_tree = NULL;
1424         int offset = 0;
1425         guint8 nlsp_major_version;
1426         guint8 nlsp_header_length;
1427         guint8 packet_type_flags;
1428         guint8 packet_type;
1429
1430         if (check_col(pinfo->cinfo, COL_PROTOCOL))
1431                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "NLSP");
1432         if (check_col(pinfo->cinfo, COL_INFO))
1433                 col_clear(pinfo->cinfo, COL_INFO);
1434
1435         nlsp_major_version = tvb_get_guint8(tvb, 5);
1436         if (nlsp_major_version != 1){
1437                 if (check_col(pinfo->cinfo, COL_INFO)) {
1438                         col_add_fstr(pinfo->cinfo, COL_INFO,
1439                                 "Unknown NLSP version (%u vs 1)",
1440                                 nlsp_major_version);
1441                 }
1442                 nlsp_dissect_unknown(tvb, tree, 0,
1443                         "Unknown NLSP version (%d vs 1)",
1444                         nlsp_major_version, 1);
1445                 return;
1446         }
1447
1448         if (tree) {
1449                 ti = proto_tree_add_item(tree, proto_nlsp, tvb, 0, -1, FALSE);
1450                 nlsp_tree = proto_item_add_subtree(ti, ett_nlsp);
1451         }
1452
1453         if (tree) {
1454                 proto_tree_add_item(nlsp_tree, hf_nlsp_irpd, tvb, offset, 1,
1455                         FALSE );
1456         }
1457         offset += 1;
1458
1459         nlsp_header_length = tvb_get_guint8(tvb, 1);
1460         if (tree) {
1461                 proto_tree_add_uint(nlsp_tree, hf_nlsp_header_length, tvb,
1462                         offset, 1, nlsp_header_length );
1463         }
1464         offset += 1;
1465
1466         if (tree) {
1467                 proto_tree_add_item(nlsp_tree, hf_nlsp_minor_version, tvb,
1468                         offset, 1, FALSE );
1469         }
1470         offset += 1;
1471
1472         offset += 1;    /* Reserved */
1473
1474         packet_type_flags = tvb_get_guint8(tvb, offset);
1475         packet_type = packet_type_flags & PACKET_TYPE_MASK;
1476         if (check_col(pinfo->cinfo, COL_INFO)) {
1477                 col_add_str(pinfo->cinfo, COL_INFO,
1478                     val_to_str(packet_type, nlsp_packet_type_vals, "Unknown (%u)"));
1479         }
1480         if (tree) {
1481                 if (packet_type == NLSP_TYPE_L1_LSP) {
1482                         proto_tree_add_boolean(nlsp_tree, hf_nlsp_nr, tvb, offset, 1,
1483                             packet_type_flags );
1484                 }
1485                 proto_tree_add_uint(nlsp_tree, hf_nlsp_type, tvb, offset, 1,
1486                     packet_type_flags );
1487         }
1488         offset += 1;
1489
1490         if (tree) {
1491                 proto_tree_add_item(nlsp_tree, hf_nlsp_major_version, tvb,
1492                         offset, 1, FALSE );
1493         }
1494         offset += 1;
1495
1496         offset += 2;    /* Reserved */
1497
1498         switch (packet_type) {
1499
1500         case NLSP_TYPE_L1_HELLO:
1501         case NLSP_TYPE_WAN_HELLO:
1502                 nlsp_dissect_nlsp_hello(tvb, pinfo, nlsp_tree, offset,
1503                     packet_type, nlsp_header_length);
1504                 break;
1505
1506         case NLSP_TYPE_L1_LSP:
1507                 nlsp_dissect_nlsp_lsp(tvb, pinfo, nlsp_tree, offset,
1508                     nlsp_header_length);
1509                 break;
1510
1511         case NLSP_TYPE_L1_CSNP:
1512                 nlsp_dissect_nlsp_csnp(tvb, pinfo, nlsp_tree, offset,
1513                     nlsp_header_length);
1514                 break;
1515
1516         case NLSP_TYPE_L1_PSNP:
1517                 nlsp_dissect_nlsp_psnp(tvb, pinfo, nlsp_tree, offset,
1518                     nlsp_header_length);
1519                 break;
1520
1521         default:
1522                 nlsp_dissect_unknown(tvb, tree, offset,
1523                         "Unknown NLSP packet type");
1524         }
1525 }
1526
1527 /*
1528  * Name: proto_register_nlsp()
1529  *
1530  * Description:
1531  *      main register for NLSP protocol set.  We register some display
1532  *      formats and the protocol module variables.
1533  *
1534  *      NOTE: this procedure to autolinked by the makefile process that
1535  *      builds register.c
1536  *
1537  * Input:
1538  *      void
1539  *
1540  * Output:
1541  *      void
1542  */
1543 void
1544 proto_register_nlsp(void)
1545 {
1546         static hf_register_info hf[] = {
1547             { &hf_nlsp_irpd,
1548               { "NetWare Link Services Protocol Discriminator", "nlsp.irpd",
1549                 FT_UINT8, BASE_HEX, NULL, 0x0, "", HFILL }},
1550
1551             { &hf_nlsp_header_length,
1552               { "PDU Header Length", "nlsp.header_length",
1553                 FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1554
1555             { &hf_nlsp_minor_version,
1556               { "Minor Version", "nlsp.minor_version", FT_UINT8,
1557                  BASE_DEC, NULL, 0x0, "", HFILL }},
1558
1559             { &hf_nlsp_nr,
1560               { "Multi-homed Non-routing Server", "nlsp.nr", FT_BOOLEAN, 8,
1561                 NULL, 0x80, "", HFILL }},
1562
1563             { &hf_nlsp_type,
1564               { "Packet Type", "nlsp.type", FT_UINT8, BASE_DEC,
1565                 VALS(nlsp_packet_type_vals), PACKET_TYPE_MASK, "", HFILL }},
1566
1567             { &hf_nlsp_major_version,
1568               { "Major Version", "nlsp.major_version", FT_UINT8,
1569                  BASE_DEC, NULL, 0x0, "", HFILL }},
1570
1571             { &hf_nlsp_packet_length,
1572               { "Packet Length", "nlsp.packet_length",
1573                 FT_UINT16, BASE_DEC, NULL, 0x0, "", HFILL }},
1574
1575             { &hf_nlsp_hello_state,
1576               { "State", "nlsp.hello.state", FT_UINT8, BASE_DEC,
1577                 VALS(nlsp_hello_state_vals), NLSP_HELLO_STATE_MASK,
1578                 "", HFILL }},
1579
1580             { &hf_nlsp_hello_multicast,
1581               { "Multicast Routing", "nlsp.hello.multicast", FT_BOOLEAN, 8,
1582                 TFS(&supported_string), NLSP_HELLO_MULTICAST_MASK,
1583                 "If set, this router supports multicast routing", HFILL }},
1584
1585             { &hf_nlsp_hello_circuit_type,
1586               { "Circuit Type", "nlsp.hello.circuit_type", FT_UINT8, BASE_DEC,
1587                 VALS(nlsp_hello_circuit_type_vals), NLSP_HELLO_CTYPE_MASK,
1588                 "", HFILL }},
1589
1590             { &hf_nlsp_hello_holding_timer,
1591               { "Holding Timer", "nlsp.hello.holding_timer", FT_UINT8, BASE_DEC,
1592                 NULL, 0x0, "", HFILL }},
1593
1594             { &hf_nlsp_hello_priority,
1595               { "Priority", "nlsp.hello.priority", FT_UINT8, BASE_DEC,
1596                 NULL, NLSP_HELLO_PRIORITY_MASK,
1597                 "", HFILL }},
1598
1599             { &hf_nlsp_lsp_sequence_number,
1600               { "Sequence Number", "nlsp.sequence_number",
1601                 FT_UINT32, BASE_HEX, NULL, 0x0, "", HFILL }},
1602
1603             { &hf_nlsp_lsp_checksum,
1604               { "Checksum", "nlsp.lsp.checksum",
1605                 FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
1606
1607             { &hf_nlsp_lsp_p,
1608               { "Partition Repair", "nlsp.lsp.partition_repair", FT_BOOLEAN, 8,
1609                 TFS(&supported_string), NLSP_LSP_PARTITION_MASK,
1610                 "If set, this router supports the optional Partition Repair function", HFILL }},
1611
1612             { &hf_nlsp_lsp_attached_flag,
1613               { "Attached Flag", "nlsp.lsp.attached_flag", FT_UINT8, BASE_DEC,
1614                 VALS(nlsp_attached_flag_vals), NLSP_LSP_ATT_MASK, "", HFILL }},
1615
1616             { &hf_nlsp_lsp_lspdbol,
1617               { "LSP Database Overloaded", "nlsp.lsp.lspdbol", FT_BOOLEAN, 8,
1618                 NULL, NLSP_LSP_OVERFLOW_MASK, "", HFILL }},
1619
1620             { &hf_nlsp_lsp_router_type,
1621               { "Router Type", "nlsp.lsp.router_type", FT_UINT8, BASE_DEC,
1622                 VALS(nlsp_router_type_vals), NLSP_LSP_ROUTER_TYPE_MASK,
1623                 "", HFILL }},
1624         };
1625         static gint *ett[] = {
1626                 &ett_nlsp,
1627                 &ett_nlsp_hello_clv_area_addr,
1628                 &ett_nlsp_hello_clv_neighbors,
1629                 &ett_nlsp_hello_local_mtu,
1630                 &ett_nlsp_hello_clv_unknown,
1631                 &ett_nlsp_lsp_info,
1632                 &ett_nlsp_lsp_clv_area_addr,
1633                 &ett_nlsp_lsp_clv_mgt_info,
1634                 &ett_nlsp_lsp_clv_link_info,
1635                 &ett_nlsp_lsp_clv_svcs_info,
1636                 &ett_nlsp_lsp_clv_ext_routes,
1637                 &ett_nlsp_lsp_clv_unknown,
1638                 &ett_nlsp_csnp_lsp_entries,
1639                 &ett_nlsp_csnp_lsp_entry,
1640                 &ett_nlsp_csnp_clv_unknown,
1641                 &ett_nlsp_psnp_lsp_entries,
1642                 &ett_nlsp_psnp_lsp_entry,
1643                 &ett_nlsp_psnp_clv_unknown,
1644         };
1645
1646         proto_nlsp = proto_register_protocol("NetWare Link Services Protocol",
1647             "NLSP", "nlsp");
1648         proto_register_field_array(proto_nlsp, hf, array_length(hf));
1649         proto_register_subtree_array(ett, array_length(ett));
1650 }
1651
1652 void
1653 proto_reg_handoff_nlsp(void)
1654 {
1655         dissector_handle_t nlsp_handle;
1656
1657         nlsp_handle = create_dissector_handle(dissect_nlsp, proto_nlsp);
1658         dissector_add("ipx.socket", IPX_SOCKET_NLSP, nlsp_handle);
1659 }