Don't do fcn calls in arg of g_?to??(); Macro may very well eval args multiple times.
[obnox/wireshark/wip.git] / epan / dissectors / packet-dlsw.c
1 /* packet-dlsw.c
2  * Routines for DLSw packet dissection (Data Link Switching)
3  * Copyright 2001, Paul Ionescu <paul@acorp.ro>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 /* DLSw dissector ( RFC 1434, RFC 1795, RFC 2166) */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <glib.h>
33 #include <epan/packet.h>
34 #include "packet-tcp.h"
35
36 static int proto_dlsw = -1;
37
38 static gint ett_dlsw = -1;
39 static gint ett_dlsw_header = -1;
40 static gint ett_dlsw_fc = -1;
41 static gint ett_dlsw_sspflags = -1;
42 static gint ett_dlsw_data = -1;
43 static gint ett_dlsw_vector = -1;
44
45 #define  CANUREACH               0x03
46 #define  ICANREACH               0x04
47 #define  REACH_ACK               0x05
48 #define  DGRMFRAME               0x06
49 #define  XIDFRAME                0x07
50 #define  CONTACT                 0x08
51 #define  CONTACTED               0x09
52 #define  RESTART_DL              0x10
53 #define  DL_RESTARTED            0x11
54 #define  ENTER_BUSY              0x0C
55 #define  EXIT_BUSY               0x0D
56 #define  INFOFRAME               0x0A
57 #define  HALT_DL                 0x0E
58 #define  DL_HALTED               0x0F
59 #define  NETBIOS_NQ              0x12
60 #define  NETBIOS_NR              0x13
61 #define  DATAFRAME               0x14
62 #define  HALT_DL_NOACK           0x19
63 #define  NETBIOS_ANQ             0x1A
64 #define  NETBIOS_ANR             0x1B
65 #define  KEEPALIVE               0x1D
66 #define  CAP_EXCHANGE            0x20
67 #define  IFCM                    0x21
68 #define  TEST_CIRCUIT_REQ        0x7A
69 #define  TEST_CIRCUIT_RSP        0x7B
70
71 static const value_string dlsw_type_vals[] = {
72         { CANUREACH        , "Can U Reach Station-circuit start" },
73         { ICANREACH        , "I Can Reach Station-circuit start" },
74         { REACH_ACK        , "Reach Acknowledgment" },
75         { DGRMFRAME        , "Datagram Frame" },
76         { XIDFRAME         , "XID Frame" },
77         { CONTACT          , "Contact Remote Station" },
78         { CONTACTED        , "Remote Station Contacted" },
79         { RESTART_DL       , "Restart Data Link" },
80         { DL_RESTARTED     , "Data Link Restarted" },
81         { ENTER_BUSY       , "Enter Busy" },
82         { EXIT_BUSY        , "Exit Busy" },
83         { INFOFRAME        , "Information (I) Frame" },
84         { HALT_DL          , "Halt Data Link" },
85         { DL_HALTED        , "Data Link Halted" },
86         { NETBIOS_NQ       , "NETBIOS Name Query-circuit setup" },
87         { NETBIOS_NR       , "NETBIOS Name Recog-circuit setup" },
88         { DATAFRAME        , "Data Frame" },
89         { HALT_DL_NOACK    , "Halt Data Link with no Ack" },
90         { NETBIOS_ANQ      , "NETBIOS Add Name Query" },
91         { NETBIOS_ANR      , "NETBIOS Add Name Response" },
92         { KEEPALIVE        , "Transport Keepalive Message" },
93         { CAP_EXCHANGE     , "Capabilities Exchange" },
94         { IFCM             , "Independent Flow Control Message" },
95         { TEST_CIRCUIT_REQ , "Test Circuit Request" },
96         { TEST_CIRCUIT_RSP , "Test Circuit Response" },
97         { 0 , NULL }
98 };
99 static const value_string dlsw_version_vals[] = {
100         { 0x31        , "Version 1 (RFC 1795)" },
101         { 0x32        , "Version 2 (RFC 2166)" },
102         { 0x33        , "Vendor Specific" },
103         { 0x34        , "Vendor Specific" },
104         { 0x35        , "Vendor Specific" },
105         { 0x36        , "Vendor Specific" },
106         { 0x37        , "Vendor Specific" },
107         { 0x38        , "Vendor Specific" },
108         { 0x39        , "Vendor Specific" },
109         { 0x3A        , "Vendor Specific" },
110         { 0x3B        , "Vendor Specific" },
111         { 0x3C        , "Vendor Specific" },
112         { 0x3D        , "Vendor Specific" },
113         { 0x3E        , "Vendor Specific" },
114         { 0x3F        , "Vendor Specific" },
115         { 0x4B        , "Pre 1 (RFC 1434)" },
116         { 0x00        , NULL }
117 };
118
119 static const value_string dlsw_fc_cmd_vals[] = {
120         { 0x00        , "Repeat Window" },
121         { 0x01        , "Increment Window" },
122         { 0x02        , "Decrement Window" },
123         { 0x03        , "Reset Window" },
124         { 0x04        , "Halve Window" },
125         { 0x00        , NULL }
126 };
127
128 static const value_string dlsw_capex_type_vals[] = {
129         { 0x01        , "Capabilities request" },
130         { 0x02        , "Capabilities response" },
131         { 0x00        , NULL }
132 };
133
134 static const value_string dlsw_frame_direction_vals[] = {
135         { 0x01        , "Origin DLSw to target DLSw" },
136         { 0x02        , "Target DLSw to origin DLSw" },
137         { 0x00        , NULL }
138 };
139
140 static const value_string dlsw_vector_vals[] = {
141         { 0x81        , "Vendor ID Control Vector" },
142         { 0x82        , "DLSw Version Control Vector" },
143         { 0x83        , "Initial Pacing Window Control Vector" },
144         { 0x84        , "Version String Control Vector" },
145         { 0x85        , "Mac Address Exclusivity Control Vector" },
146         { 0x86        , "Supported SAP List Control Vector" },
147         { 0x87        , "TCP Connections Control Vector" },
148         { 0x88        , "NetBIOS Name Exclusivity Control Vector" },
149         { 0x89        , "MAC Address List Control Vector" },
150         { 0x8a        , "NetBIOS Name List Control Vector" },
151         { 0x8b        , "Vendor Context Control Vector" },
152         { 0x8c        , "Multicast Capabilities Control Vector" },
153         { 0x8d        , "Reserved for future use" },
154         { 0x8e        , "Reserved for future use" },
155         { 0x8f        , "Reserved for future use" },
156         { 0x90        , "Reserved for future use" },
157         { 0x91        , " Control Vector" },
158         { 0x92        , " Control Vector" },
159         { 0x93        , " Control Vector" },
160         { 0x94        , " Control Vector" },
161         { 0x95        , " Control Vector" },
162         { 0x96        , " Control Vector" },
163         { 0x00        , NULL }
164 };
165
166 static const value_string dlsw_pri_vals[] = {
167         { 0        , "Unsupported" },
168         { 1        , "Low Priority" },
169         { 2        , "Medium Priority" },
170         { 3        , "High Priority" },
171         { 4        , "Highest Priority" },
172         { 5        , "Reserved" },
173         { 6        , "Reserved" },
174         { 7        , "Reserved" },
175         { 0, NULL }
176 };
177
178
179
180
181 #define DLSW_GDSID_SEND         0x1520
182 #define DLSW_GDSID_ACK          0x1521
183 #define DLSW_GDSID_REF          0x1522
184
185 static const value_string dlsw_gds_vals[] = {
186         { DLSW_GDSID_SEND , "Request Capabilities GDS" },
187         { DLSW_GDSID_ACK  , "Response Capabilities GDS" },
188         { DLSW_GDSID_REF  , "Refuse Capabilities GDS" },
189         { 0               , NULL }
190 };
191
192 static const value_string dlsw_refuse_vals[] = {
193         { 0x1   , "invalid GDS length for a DLWs Capabilities Exchange Request"},
194         { 0x2   , "invalid GDS id for a DLSw Capabilities Exchange Request"},
195         { 0x3   , "vendor Id control vector is missing"},
196         { 0x4   , "DLSw Version control vector is missing"},
197         { 0x5   , "initial Pacing Window control vector is missing"},
198         { 0x6   , "length of control vectors doesn't correlate to the length of the GDS variable"},
199         { 0x7   , "invalid control vector id"},
200         { 0x8   , "length of control vector invalid"},
201         { 0x9   , "invalid control vector data value"},
202         { 0xa   , "duplicate control vector"},
203         { 0xb   , "out-of-sequence control vector"},
204         { 0xc   , "DLSw Supported SAP List control vector is missing"},
205         { 0xd   , "inconsistent DLSw Version, Multicast Capabilities, and TCP Connections CV received on the inbound Capabilities exchange"},
206         { 0x0   , NULL }
207 };
208
209 #define UDP_PORT_DLSW           2067
210 #define TCP_PORT_DLSW           2065
211 #define DLSW_INFO_HEADER        16
212 #define DLSW_CMD_HEADER         72
213
214 static void
215 dissect_dlsw_capex(tvbuff_t *tvb, proto_tree *tree, proto_tree *ti);
216
217 static void
218 dissect_dlsw_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
219 {
220  guint version,hlen = 0,mlen = 0,mtype,dlchlen = 0,direction,flags;
221  proto_tree      *dlsw_tree = NULL, *ti,*ti2, *dlsw_header_tree = NULL;
222  proto_tree      *dlsw_flags_tree,*dlsw_data_tree;
223
224  col_set_str(pinfo->cinfo, COL_PROTOCOL, "DLSw");
225
226  version=tvb_get_guint8(tvb,0);
227
228  col_add_fstr(pinfo->cinfo, COL_INFO, "DLSw %s",val_to_str(version , dlsw_version_vals, "Unknown Version"));
229
230  if (tree)
231  {
232    ti = proto_tree_add_item(tree, proto_dlsw, tvb, 0, -1, ENC_NA);
233    dlsw_tree = proto_item_add_subtree(ti, ett_dlsw);
234
235    hlen=tvb_get_guint8(tvb,1);
236
237    ti2 = proto_tree_add_text (dlsw_tree, tvb, 0, hlen,"DLSw header, %s",
238      val_to_str(version , dlsw_version_vals, "Unknown Version"));
239
240    dlsw_header_tree = proto_item_add_subtree(ti2, ett_dlsw_header);
241    proto_tree_add_text (dlsw_header_tree,tvb,0 ,1,"Version        = %s",
242     val_to_str(version , dlsw_version_vals, "Unknown Version, dissection may be inaccurate"));
243    proto_tree_add_text (dlsw_header_tree,tvb,1 ,1,"Header Length  = %u",hlen) ;
244    mlen=tvb_get_ntohs(tvb,2);
245    proto_tree_add_text (dlsw_header_tree,tvb,2 ,2,"Message Length = %u",mlen);
246    proto_tree_add_text (dlsw_header_tree,tvb,4 ,4,"Remote DLC     = %u",tvb_get_ntohl(tvb,4)) ;
247    proto_tree_add_text (dlsw_header_tree,tvb,8 ,4,"Remote DLC PID = %u",tvb_get_ntohl(tvb,8)) ;
248    proto_tree_add_text (dlsw_header_tree,tvb,12,2,"Reserved") ;
249   } ;
250
251   mtype=tvb_get_guint8(tvb,14);
252   col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",val_to_str(mtype , dlsw_type_vals, "Unknown message Type"));
253   if (tree)
254   {
255    proto_tree_add_text (dlsw_header_tree,tvb,14,1,"Message Type   = %s (0x%02x)",
256     val_to_str(mtype , dlsw_type_vals, "Unknown Type"),mtype);
257    if (mtype==CAP_EXCHANGE)
258     {
259      proto_tree_add_text (dlsw_header_tree,tvb, 15,1,"Not used for CapEx") ;
260     }
261    else
262     {
263     flags = tvb_get_guint8(tvb,15);
264     ti2 = proto_tree_add_text (dlsw_header_tree, tvb, 15,1,"Flow ctrl byte = 0x%02x",flags);
265     dlsw_flags_tree = proto_item_add_subtree(ti2, ett_dlsw_fc);
266     proto_tree_add_text (dlsw_flags_tree, tvb, 15, 1, "%s",
267         decode_boolean_bitfield(flags, 0x80, 8,
268                                 "Flow Control Indication: yes",
269                                 "Flow Control Indication: no"));
270     if (flags & 0x80)
271      {
272      proto_tree_add_text (dlsw_flags_tree, tvb, 15, 1, "%s",
273         decode_boolean_bitfield(flags, 0x40, 8,
274                                 "Flow Control Acknowledgment: yes",
275                                 "Flow Control Acknowledgment: no"));
276      proto_tree_add_text (dlsw_flags_tree, tvb, 15, 1, "%s",
277         decode_enumerated_bitfield(flags, 0x07, 8,
278            dlsw_fc_cmd_vals, "Flow Control Operator: %s"));
279      }
280     }
281    if (hlen != DLSW_INFO_HEADER)
282     {
283     if (mtype==CAP_EXCHANGE)
284      {
285      proto_tree_add_text (dlsw_header_tree,tvb, 16,1,"Protocol ID    = 0x%02x",tvb_get_guint8(tvb,16)) ;
286      proto_tree_add_text (dlsw_header_tree,tvb, 17,1,"Header Number  = 0x%02x",tvb_get_guint8(tvb,17)) ;
287      proto_tree_add_text (dlsw_header_tree,tvb, 18,5,"Not used for CapEx") ;
288      proto_tree_add_text (dlsw_header_tree,tvb, 23,1,"Old message type = %s (0x%02x)",
289      val_to_str(tvb_get_guint8(tvb,23) , dlsw_type_vals, "Unknown Type"),
290      tvb_get_guint8(tvb,23));
291      direction=tvb_get_guint8(tvb,38);
292      proto_tree_add_text (dlsw_header_tree,tvb, 24,14,"Not used for CapEx") ;
293      proto_tree_add_text (dlsw_header_tree,tvb, 38,1,"Frame direction   =  %s (0x%02x)",
294       val_to_str(direction , dlsw_capex_type_vals, "Unknown Direction"),
295       direction);
296      proto_tree_add_text (dlsw_header_tree,tvb, 39,33,"Not used for CapEx") ;
297      }
298     else
299      {
300      proto_tree_add_text (dlsw_header_tree,tvb, 16,1,"Protocol ID    = 0x%02x",tvb_get_guint8(tvb,16)) ;
301      proto_tree_add_text (dlsw_header_tree,tvb, 17,1,"Header Number  = 0x%02x",tvb_get_guint8(tvb,17)) ;
302      proto_tree_add_text (dlsw_header_tree,tvb, 18,2,"Reserved") ;
303      proto_tree_add_text (dlsw_header_tree,tvb, 20,1,"Largest Frame size  = %u",tvb_get_guint8(tvb,20)) ;
304      flags = tvb_get_guint8(tvb,21);
305      ti2 = proto_tree_add_text (dlsw_header_tree,tvb, 21,1,"SSP Flags      = 0x%02x",flags) ;
306      dlsw_flags_tree = proto_item_add_subtree(ti2, ett_dlsw_sspflags);
307      proto_tree_add_text (dlsw_flags_tree, tvb, 21, 1, "%s",
308         decode_boolean_bitfield(flags, 0x80, 8,
309                                 "Explorer message: yes",
310                                 "Explorer message: no"));
311      proto_tree_add_text (dlsw_header_tree,tvb, 22,1,"Circuit priority = %s",
312                           val_to_str((tvb_get_guint8(tvb,22)&7),dlsw_pri_vals, "Unknown (%d)")) ;
313      proto_tree_add_text (dlsw_header_tree,tvb, 23,1,"Old message type = %s (0x%02x)",
314                           val_to_str(tvb_get_guint8(tvb,23) , dlsw_type_vals, "Unknown Type"),
315      tvb_get_guint8(tvb,23));
316      proto_tree_add_text (dlsw_header_tree,tvb, 24,6,"Target MAC Address  = %s",tvb_bytes_to_str(tvb,24,6)) ;
317      proto_tree_add_text (dlsw_header_tree,tvb, 30,6,"Origin MAC Address  = %s",tvb_bytes_to_str(tvb,30,6)) ;
318      proto_tree_add_text (dlsw_header_tree,tvb, 36,1,"Origin Link SAP     = 0x%02x",tvb_get_guint8(tvb,36)) ;
319      proto_tree_add_text (dlsw_header_tree,tvb, 37,1,"Target Link SAP     = 0x%02x",tvb_get_guint8(tvb,37)) ;
320      direction=tvb_get_guint8(tvb,38);
321      proto_tree_add_text (dlsw_header_tree,tvb, 38,1,"Frame direction   =  %s (0x%02x)",
322       val_to_str(direction , dlsw_frame_direction_vals, "Unknown Direction"),
323       direction);
324      proto_tree_add_text (dlsw_header_tree,tvb, 39,3,"Reserved") ;
325      dlchlen=tvb_get_ntohs(tvb,42);
326      if ( dlchlen > mlen )
327       {
328       proto_tree_add_text (dlsw_header_tree,tvb, 42,2,"DLC Header Length = %u (bogus, must be <= message length %u)",dlchlen, mlen) ;
329       return;
330       }
331      proto_tree_add_text (dlsw_header_tree,tvb, 42,2,"DLC Header Length = %u",dlchlen) ;
332      proto_tree_add_text (dlsw_header_tree,tvb, 44,4,"Origin DLC Port ID     = %u",tvb_get_ntohl(tvb,44)) ;
333      proto_tree_add_text (dlsw_header_tree,tvb, 48,4,"Origin DLC             = %u",tvb_get_ntohl(tvb,48)) ;
334      proto_tree_add_text (dlsw_header_tree,tvb, 52,4,"Origin Transport ID    = %u",tvb_get_ntohl(tvb,52)) ;
335      proto_tree_add_text (dlsw_header_tree,tvb, 56,4,"Target DLC Port ID     = %u",tvb_get_ntohl(tvb,56)) ;
336      proto_tree_add_text (dlsw_header_tree,tvb, 60,4,"Target DLC             = %u",tvb_get_ntohl(tvb,60)) ;
337      proto_tree_add_text (dlsw_header_tree,tvb, 64,4,"Target Transport ID    = %u",tvb_get_ntohl(tvb,64)) ;
338      proto_tree_add_text (dlsw_header_tree,tvb, 68,4,"Reserved") ;
339      }
340     }
341
342 /* end of header dissector */
343
344     ti2 = proto_tree_add_text (dlsw_tree, tvb, hlen, mlen,"DLSw data");
345     dlsw_data_tree = proto_item_add_subtree(ti2, ett_dlsw_data);
346
347     switch (mtype)
348       {
349       case CAP_EXCHANGE:
350         dissect_dlsw_capex(tvb_new_subset(tvb, hlen, mlen, -1), dlsw_data_tree,ti2);
351         break;
352       case IFCM:
353       case INFOFRAME:
354       case KEEPALIVE:
355         proto_tree_add_text (dlsw_data_tree,tvb,hlen,mlen,"Data") ;
356         break;
357
358       default:
359         if (dlchlen!=0)
360          {
361          proto_tree_add_text (dlsw_data_tree,tvb,hlen,1,"DLC Header - AC byte : 0x%02x",tvb_get_guint8(tvb,hlen)) ;
362          proto_tree_add_text (dlsw_data_tree,tvb,hlen+1,1,"DLC Header - FC byte : 0x%02x",tvb_get_guint8(tvb,hlen+1)) ;
363          proto_tree_add_text (dlsw_data_tree,tvb,hlen+2,6,"DLC Header - DA : %s",tvb_bytes_to_str(tvb,hlen+2,6)) ;
364          proto_tree_add_text (dlsw_data_tree,tvb,hlen+8,6,"DLC Header - SA : %s",tvb_bytes_to_str(tvb,hlen+8,6)) ;
365          proto_tree_add_text (dlsw_data_tree,tvb,hlen+14,18,"DLC Header - RIF : %s",tvb_bytes_to_str(tvb,hlen+14,18)) ;
366          proto_tree_add_text (dlsw_data_tree,tvb,hlen+32,1,"DLC Header - DSAP : 0x%02x",tvb_get_guint8(tvb,hlen+32)) ;
367          proto_tree_add_text (dlsw_data_tree,tvb,hlen+33,1,"DLC Header - SSAP : 0x%02x",tvb_get_guint8(tvb,hlen+33)) ;
368          proto_tree_add_text (dlsw_data_tree,tvb,hlen+34,1,"DLC Header - Ctrl : 0x%02x",tvb_get_guint8(tvb,hlen+34)) ;
369          }
370         proto_tree_add_text (dlsw_data_tree,tvb,hlen+dlchlen,mlen-dlchlen,"Data") ;
371       }
372
373    }
374 }
375
376 static void
377 dissect_dlsw_capex(tvbuff_t *tvb, proto_tree *tree, proto_tree *ti2)
378 {
379  int mlen,vlen,vtype,offset=4,gdsid,sap,i=0;
380  proto_tree *ti,*dlsw_vector_tree;
381  mlen=tvb_get_ntohs(tvb,0);
382  gdsid=tvb_get_ntohs(tvb,2);
383  proto_tree_add_text (tree,tvb,0,2,"Capabilities Length =  %d",mlen) ;
384  proto_tree_add_text (tree,tvb,2,2,"%s",val_to_str( gdsid, dlsw_gds_vals, "Invalid GDS ID"));
385  proto_item_append_text(ti2," - %s",val_to_str( gdsid, dlsw_gds_vals, "Invalid GDS ID"));
386  switch (gdsid) {
387   case DLSW_GDSID_ACK:
388     break;
389   case DLSW_GDSID_REF:
390     proto_tree_add_text (tree,tvb,4,2,"Error pointer =  %d",tvb_get_ntohs(tvb,4));
391     proto_tree_add_text (tree,tvb,6,2,"Error cause = %s",
392      val_to_str(tvb_get_ntohs(tvb,6), dlsw_refuse_vals, "Unknown refuse cause"));
393     break;
394   case DLSW_GDSID_SEND:
395     while (offset < mlen){
396       vlen=tvb_get_guint8(tvb,offset);
397       if (vlen < 3) THROW(ReportedBoundsError);
398       vtype=tvb_get_guint8(tvb,offset+1);
399       ti=proto_tree_add_text (tree,tvb,offset,vlen,"%s",
400          val_to_str(vtype,dlsw_vector_vals,"Unknown vector type"));
401       dlsw_vector_tree = proto_item_add_subtree(ti, ett_dlsw_vector);
402       proto_tree_add_text (dlsw_vector_tree,tvb,offset,1,  "Vector Length = %d",vlen);
403       proto_tree_add_text (dlsw_vector_tree,tvb,offset+1,1,"Vector Type   = %s (0x%02x)",
404        val_to_str(vtype,dlsw_vector_vals,"Unknown vector type"),vtype);
405       switch (vtype){
406         case 0x81:
407           proto_tree_add_text (dlsw_vector_tree,tvb,offset+2,vlen-2,
408            "OUI = 0x%06x",tvb_get_ntoh24(tvb,offset+2));
409           break;
410         case 0x82:
411           proto_tree_add_text (dlsw_vector_tree,tvb,offset+2,vlen-2,
412            "DLSw Version = %d.%d",tvb_get_guint8(tvb,offset+2),tvb_get_guint8(tvb,offset+3));
413           break;
414         case 0x83:
415           proto_tree_add_text (dlsw_vector_tree,tvb,offset+2,vlen-2,
416            "Initial Pacing Window = %d",tvb_get_ntohs(tvb,offset+2));
417           break;
418         case 0x84:
419            proto_tree_add_text (dlsw_vector_tree,tvb,offset+2,vlen-2,
420            "Version String = %s",tvb_format_text(tvb,offset+2,vlen-2));
421           break;
422         case 0x85:
423           proto_tree_add_text (dlsw_vector_tree,tvb,offset+2,vlen-2,
424            "MAC Address Exclusivity = %s",tvb_get_guint8(tvb,offset+2)==1?"On":"Off");
425           break;
426         case 0x86:
427           while (i<vlen-2)
428            {
429            sap=tvb_get_guint8(tvb,offset+2+i);
430            proto_tree_add_text (dlsw_vector_tree,tvb,offset+2+i,1,
431             "SAP List Support = 0x%x0=%s 0x%x2=%s 0x%x4=%s 0x%x6=%s 0x%x8=%s 0x%xa=%s 0x%xc=%s 0x%xe=%s",
432             i,sap&0x80?"on ":"off",i,sap&0x40?"on ":"off",i,sap&0x20?"on ":"off",i,sap&0x10?"on ":"off",
433             i,sap&0x08?"on ":"off",i,sap&0x04?"on ":"off",i,sap&0x02?"on ":"off",i,sap&0x01?"on ":"off");
434            i++;
435            }
436           break;
437         case 0x87:
438           proto_tree_add_text (dlsw_vector_tree,tvb,offset+2,vlen-2,
439            "TCP connections  = %d",tvb_get_guint8(tvb,offset+2));
440           break;
441         case 0x88:
442           proto_tree_add_text (dlsw_vector_tree,tvb,offset+2,vlen-2,
443            "NetBIOS Name Exclusivity = %s",tvb_get_guint8(tvb,offset+2)==1?"On":"Off");
444           break;
445         case 0x89:
446           proto_tree_add_text (dlsw_vector_tree,tvb,offset+2,vlen-2,
447            "MAC Address List = %s / %s",tvb_bytes_to_str(tvb,offset+2,6)
448            ,tvb_bytes_to_str(tvb,offset+8,6));
449           break;
450         case 0x8a:
451           proto_tree_add_text (dlsw_vector_tree,tvb,offset+2,vlen-2,
452 /* %s */           "NetBIOS name = %s",/* tvb_get_guint8(tvb,offset+2)==0?"Individual":"Group",*/
453            tvb_format_text(tvb,offset+2,vlen-2));
454           break;
455         case 0x8b:
456           proto_tree_add_text (dlsw_vector_tree,tvb,offset+2,vlen-2,
457            "Vendor OUI = 0x%06x",tvb_get_ntoh24(tvb,offset+2));
458           break;
459         case 0x8c:
460           proto_tree_add_text (dlsw_vector_tree,tvb,offset+2,vlen-2,
461            "Multicast Version Number = %d",tvb_get_guint8(tvb,offset+2));
462           break;
463         default:
464         proto_tree_add_text (dlsw_vector_tree,tvb,offset+2,vlen-2,"Vector Data = ???");
465         }
466       offset+=vlen;
467       };
468     break;
469   default:
470     proto_tree_add_text (tree,tvb,4,mlen - 4,"Unknown data");
471   }
472
473 }
474
475 static int
476 dissect_dlsw_udp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
477 {
478  if (match_strval(tvb_get_guint8(tvb, 0), dlsw_version_vals) == NULL)
479  {
480    /* Probably not a DLSw packet. */
481    return 0;
482  }
483
484  dissect_dlsw_pdu(tvb, pinfo, tree);
485  return tvb_length(tvb);
486 }
487
488 static guint
489 get_dlsw_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset)
490 {
491   guint hlen, mlen;
492
493   /*
494    * Get the length of the DLSw header.
495    */
496   hlen=tvb_get_guint8(tvb,offset+1);
497
498   /*
499    * Get the length of the DLSw message.
500    */
501   mlen = tvb_get_ntohs(tvb,offset+2);
502
503   /*
504    * The total length is the sum of those.
505    */
506   return hlen + mlen;
507 }
508
509 static int
510 dissect_dlsw_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
511 {
512  if (match_strval(tvb_get_guint8(tvb, 0), dlsw_version_vals) == NULL)
513  {
514    /* Probably not a DLSw packet. */
515    return 0;
516  }
517
518  tcp_dissect_pdus(tvb, pinfo, tree, TRUE, 4, get_dlsw_pdu_len,
519         dissect_dlsw_pdu);
520  return tvb_length(tvb);
521 }
522
523 void
524 proto_register_dlsw(void)
525 {
526   static gint *ett[] = {
527     &ett_dlsw,
528     &ett_dlsw_header,
529     &ett_dlsw_fc,
530     &ett_dlsw_sspflags,
531     &ett_dlsw_data,
532     &ett_dlsw_vector,
533   };
534
535   proto_dlsw = proto_register_protocol("Data Link SWitching", "DLSw", "dlsw");
536 /* proto_register_field_array(proto_dlsw, hf, array_length(hf)); */
537   proto_register_subtree_array(ett, array_length(ett));
538 }
539
540 void
541 proto_reg_handoff_dlsw(void)
542 {
543   dissector_handle_t dlsw_udp_handle, dlsw_tcp_handle;
544
545   dlsw_udp_handle = new_create_dissector_handle(dissect_dlsw_udp, proto_dlsw);
546   dissector_add_uint("udp.port", UDP_PORT_DLSW, dlsw_udp_handle);
547
548   dlsw_tcp_handle = new_create_dissector_handle(dissect_dlsw_tcp, proto_dlsw);
549   dissector_add_uint("tcp.port", TCP_PORT_DLSW, dlsw_tcp_handle);
550 }