From Didier Gautheron:
[obnox/wireshark/wip.git] / epan / dissectors / packet-spp.c
1 /* packet-spp.c
2  * Routines for XNS SPP
3  * Based on the Netware SPX dissector by Gilbert Ramirez <gram@alumni.rice.edu>
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 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <glib.h>
31 #include <epan/packet.h>
32 #include "packet-idp.h"
33
34 static int proto_spp = -1;
35 static int hf_spp_connection_control = -1;
36 static int hf_spp_connection_control_sys = -1;
37 static int hf_spp_connection_control_send_ack = -1;
38 static int hf_spp_connection_control_attn = -1;
39 static int hf_spp_connection_control_eom = -1;
40 static int hf_spp_datastream_type = -1;
41 static int hf_spp_src_id = -1;
42 static int hf_spp_dst_id = -1;
43 static int hf_spp_seq_nr = -1;
44 static int hf_spp_ack_nr = -1;
45 static int hf_spp_all_nr = -1;
46 static int hf_spp_rexmt_frame = -1;
47
48 static gint ett_spp = -1;
49 static gint ett_spp_connctrl = -1;
50
51 static dissector_handle_t data_handle;
52
53 static dissector_table_t spp_socket_dissector_table;
54
55 /*
56  * See
57  *
58  *      "Internet Transport Protocols", XSIS 028112, December 1981
59  *
60  * if you can find it; this is based on the headers in the BSD XNS
61  * implementation.
62  */
63
64 #define SPP_SYS_PACKET  0x80
65 #define SPP_SEND_ACK    0x40
66 #define SPP_ATTN        0x20
67 #define SPP_EOM         0x10
68
69 static const char*
70 spp_conn_ctrl(guint8 ctrl)
71 {
72         const char *p;
73
74         static const value_string conn_vals[] = {
75                 { 0x00,                        "Data, No Ack Required" },
76                 { SPP_EOM,                     "End-of-Message" },
77                 { SPP_ATTN,                    "Attention" },
78                 { SPP_SEND_ACK,                "Acknowledgment Required"},
79                 { SPP_SEND_ACK|SPP_EOM,        "Send Ack: End Message"},
80                 { SPP_SYS_PACKET,              "System Packet"},
81                 { SPP_SYS_PACKET|SPP_SEND_ACK, "System Packet: Send Ack"},
82                 { 0x00,                        NULL }
83         };
84
85         p = match_strval((ctrl & 0xf0), conn_vals );
86
87         if (p) {
88                 return p;
89         }
90         else {
91                 return "Unknown";
92         }
93 }
94
95 static const char*
96 spp_datastream(guint8 type)
97 {
98         switch (type) {
99                 case 0xfe:
100                         return "End-of-Connection";
101                 case 0xff:
102                         return "End-of-Connection Acknowledgment";
103                 default:
104                         return NULL;
105         }
106 }
107
108 #define SPP_HEADER_LEN  12
109
110 /*
111  * XXX - do reassembly, using the EOM flag.  (Then do that in the Netware
112  * SPX implementation, too.)
113  *
114  * XXX - hand off to subdissectors based on the socket number.
115  */
116 static void
117 dissect_spp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
118 {
119         proto_tree      *spp_tree = NULL;
120         proto_item      *ti;
121         tvbuff_t        *next_tvb;
122         guint8          conn_ctrl;
123         proto_tree      *cc_tree;
124         guint8          datastream_type;
125         const char      *datastream_type_string;
126         guint16         spp_seq;
127         const char      *spp_msg_string;
128         guint16         low_socket, high_socket;
129
130         col_set_str(pinfo->cinfo, COL_PROTOCOL, "SPP");
131         col_set_str(pinfo->cinfo, COL_INFO, "SPP");
132
133         if (tree) {
134                 ti = proto_tree_add_item(tree, proto_spp, tvb, 0, SPP_HEADER_LEN, FALSE);
135                 spp_tree = proto_item_add_subtree(ti, ett_spp);
136         }
137
138         conn_ctrl = tvb_get_guint8(tvb, 0);
139         spp_msg_string = spp_conn_ctrl(conn_ctrl);
140         if (check_col(pinfo->cinfo, COL_INFO))
141                 col_append_fstr(pinfo->cinfo, COL_INFO, " %s", spp_msg_string);
142         if (tree) {
143                 ti = proto_tree_add_uint_format(spp_tree, hf_spp_connection_control, tvb,
144                                                 0, 1, conn_ctrl,
145                                                 "Connection Control: %s (0x%02X)",
146                                                 spp_msg_string, conn_ctrl);
147                 cc_tree = proto_item_add_subtree(ti, ett_spp_connctrl);
148                 proto_tree_add_boolean(cc_tree, hf_spp_connection_control_sys, tvb,
149                                        0, 1, conn_ctrl);
150                 proto_tree_add_boolean(cc_tree, hf_spp_connection_control_send_ack, tvb,
151                                        0, 1, conn_ctrl);
152                 proto_tree_add_boolean(cc_tree, hf_spp_connection_control_attn, tvb,
153                                        0, 1, conn_ctrl);
154                 proto_tree_add_boolean(cc_tree, hf_spp_connection_control_eom, tvb,
155                                        0, 1, conn_ctrl);
156         }
157
158         datastream_type = tvb_get_guint8(tvb, 1);
159         datastream_type_string = spp_datastream(datastream_type);
160         if (datastream_type_string != NULL) {
161                 if (check_col(pinfo->cinfo, COL_INFO))
162                         col_append_fstr(pinfo->cinfo, COL_INFO, " (%s)",
163                             datastream_type_string);
164         }
165         if (tree) {
166                 if (datastream_type_string != NULL) {
167                         proto_tree_add_uint_format(spp_tree, hf_spp_datastream_type, tvb,
168                                                    1, 1, datastream_type,
169                                                    "Datastream Type: %s (0x%02X)",
170                                                    datastream_type_string,
171                                                    datastream_type);
172                 } else {
173                         proto_tree_add_uint_format(spp_tree, hf_spp_datastream_type, tvb,
174                                                    1, 1, datastream_type,
175                                                    "Datastream Type: 0x%02X",
176                                                    datastream_type);
177                 }
178                 proto_tree_add_item(spp_tree, hf_spp_src_id, tvb,  2, 2, FALSE);
179                 proto_tree_add_item(spp_tree, hf_spp_dst_id, tvb,  4, 2, FALSE);
180         }
181         spp_seq = tvb_get_ntohs(tvb, 6);
182         if (tree) {
183                 proto_tree_add_uint(spp_tree, hf_spp_seq_nr, tvb,  6, 2, spp_seq);
184                 proto_tree_add_item(spp_tree, hf_spp_ack_nr, tvb,  8, 2, FALSE);
185                 proto_tree_add_item(spp_tree, hf_spp_all_nr, tvb, 10, 2, FALSE);
186         }
187
188         if (tvb_reported_length_remaining(tvb, SPP_HEADER_LEN) > 0) {
189                 if (pinfo->srcport > pinfo->destport) {
190                         low_socket = pinfo->destport;
191                         high_socket = pinfo->srcport;
192                 } else {
193                         low_socket = pinfo->srcport;
194                         high_socket = pinfo->destport;
195                 }
196
197                 next_tvb = tvb_new_subset_remaining(tvb, SPP_HEADER_LEN);
198                 if (dissector_try_port(spp_socket_dissector_table, low_socket,
199                     next_tvb, pinfo, tree))
200                         return;
201                 if (dissector_try_port(spp_socket_dissector_table, high_socket,
202                     next_tvb, pinfo, tree))
203                         return;
204                 call_dissector(data_handle, next_tvb, pinfo, tree);
205         }
206 }
207
208
209 void
210 proto_register_spp(void)
211 {
212         static hf_register_info hf_spp[] = {
213                 { &hf_spp_connection_control,
214                 { "Connection Control",         "spp.ctl",
215                   FT_UINT8,     BASE_HEX,       NULL,   0x0,
216                   NULL, HFILL }},
217
218                 { &hf_spp_connection_control_sys,
219                 { "System Packet",              "spp.ctl.sys",
220                   FT_BOOLEAN,   8,      NULL,   SPP_SYS_PACKET,
221                   NULL, HFILL }},
222
223                 { &hf_spp_connection_control_send_ack,
224                 { "Send Ack",           "spp.ctl.send_ack",
225                   FT_BOOLEAN,   8,      NULL,   SPP_SEND_ACK,
226                   NULL, HFILL }},
227
228                 { &hf_spp_connection_control_attn,
229                 { "Attention",          "spp.ctl.attn",
230                   FT_BOOLEAN,   8,      NULL,   SPP_ATTN,
231                   NULL, HFILL }},
232
233                 { &hf_spp_connection_control_eom,
234                 { "End of Message",     "spp.ctl.eom",
235                   FT_BOOLEAN,   8,      NULL,   SPP_EOM,
236                   NULL, HFILL }},
237
238                 { &hf_spp_datastream_type,
239                 { "Datastream type",            "spp.type",
240                   FT_UINT8,     BASE_HEX,       NULL,   0x0,
241                   NULL, HFILL }},
242
243                 { &hf_spp_src_id,
244                 { "Source Connection ID",       "spp.src",
245                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
246                   NULL, HFILL }},
247
248                 { &hf_spp_dst_id,
249                 { "Destination Connection ID",  "spp.dst",
250                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
251                   NULL, HFILL }},
252
253                 { &hf_spp_seq_nr,
254                 { "Sequence Number",            "spp.seq",
255                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
256                   NULL, HFILL }},
257
258                 { &hf_spp_ack_nr,
259                 { "Acknowledgment Number",      "spp.ack",
260                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
261                   NULL, HFILL }},
262
263                 { &hf_spp_all_nr,
264                 { "Allocation Number",          "spp.alloc",
265                   FT_UINT16,    BASE_DEC,       NULL,   0x0,
266                   NULL, HFILL }},
267
268                 { &hf_spp_rexmt_frame,
269                 { "Retransmitted Frame Number", "spp.rexmt_frame",
270                   FT_FRAMENUM,  BASE_NONE,      NULL,   0x0,
271                   NULL, HFILL }},
272         };
273
274         static gint *ett[] = {
275                 &ett_spp,
276                 &ett_spp_connctrl,
277         };
278
279         proto_spp = proto_register_protocol("Sequenced Packet Protocol",
280             "SPP", "spp");
281         proto_register_field_array(proto_spp, hf_spp, array_length(hf_spp));
282         proto_register_subtree_array(ett, array_length(ett));
283
284         spp_socket_dissector_table = register_dissector_table("spp.socket",
285             "SPP socket", FT_UINT16, BASE_HEX);
286 }
287
288 void
289 proto_reg_handoff_spp(void)
290 {
291         dissector_handle_t spp_handle;
292
293         spp_handle = create_dissector_handle(dissect_spp, proto_spp);
294         dissector_add("idp.packet_type", IDP_PACKET_TYPE_SPP, spp_handle);
295
296         data_handle = find_dissector("data");
297 }