Remove unneeded #include <stdio.h>
[obnox/wireshark/wip.git] / epan / dissectors / packet-lapb.c
1 /* packet-lapb.c
2  * Routines for lapb frame disassembly
3  * Olivier Abad <oabad@noos.fr>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998
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 <string.h>
32 #include <epan/packet.h>
33 #include <epan/xdlc.h>
34
35 static int proto_lapb = -1;
36 static int hf_lapb_address = -1;
37 static int hf_lapb_control = -1;
38 static int hf_lapb_n_r = -1;
39 static int hf_lapb_n_s = -1;
40 static int hf_lapb_p = -1;
41 static int hf_lapb_f = -1;
42 static int hf_lapb_s_ftype = -1;
43 static int hf_lapb_u_modifier_cmd = -1;
44 static int hf_lapb_u_modifier_resp = -1;
45 static int hf_lapb_ftype_i = -1;
46 static int hf_lapb_ftype_s_u = -1;
47
48 static gint ett_lapb = -1;
49 static gint ett_lapb_control = -1;
50
51 static dissector_handle_t x25_dir_handle;
52 static dissector_handle_t x25_handle;
53
54 static const xdlc_cf_items lapb_cf_items = {
55         &hf_lapb_n_r,
56         &hf_lapb_n_s,
57         &hf_lapb_p,
58         &hf_lapb_f,
59         &hf_lapb_s_ftype,
60         &hf_lapb_u_modifier_cmd,
61         &hf_lapb_u_modifier_resp,
62         &hf_lapb_ftype_i,
63         &hf_lapb_ftype_s_u
64 };
65
66 static void
67 dissect_lapb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
68 {
69     proto_tree          *lapb_tree, *ti;
70     int                 is_response;
71     guint8              byte0;
72     tvbuff_t            *next_tvb;
73
74     col_set_str(pinfo->cinfo, COL_PROTOCOL, "LAPB");
75     col_clear(pinfo->cinfo, COL_INFO);
76
77     switch (pinfo->p2p_dir) {
78
79     case P2P_DIR_SENT:
80         col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "DTE");
81         col_set_str(pinfo->cinfo, COL_RES_DL_DST, "DCE");
82         break;
83
84     case P2P_DIR_RECV:
85         col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "DCE");
86         col_set_str(pinfo->cinfo, COL_RES_DL_DST, "DTE");
87         break;
88
89     default:
90         col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "N/A");
91         col_set_str(pinfo->cinfo, COL_RES_DL_DST, "N/A");
92         break;
93     }
94
95     byte0 = tvb_get_guint8(tvb, 0);
96
97     if (byte0 != 0x01 && byte0 != 0x03 && byte0 != 0x07 && byte0 != 0x0f) /* invalid LAPB frame */
98     {
99         col_set_str(pinfo->cinfo, COL_INFO, "Invalid LAPB frame");
100         if (tree)
101             proto_tree_add_protocol_format(tree, proto_lapb, tvb, 0, -1,
102                             "Invalid LAPB frame");
103         return;
104     }
105
106     switch (pinfo->p2p_dir) {
107
108     case P2P_DIR_SENT:
109         if (byte0 == 0x03)
110             is_response = TRUE;
111         else
112             is_response = FALSE;
113         break;
114
115     case P2P_DIR_RECV:
116         if (byte0 == 0x01)
117             is_response = TRUE;
118         else
119             is_response = FALSE;
120         break;
121
122     default:
123         /*
124          * XXX - should we base this on the source and destination
125          * addresses?  The problem is that we can tell one direction
126          * from another with that, but we can't say which is DTE->DCE
127          * and which is DCE->DTE.
128          */
129         is_response = FALSE;
130         break;
131     }
132
133     if (tree) {
134         ti = proto_tree_add_protocol_format(tree, proto_lapb, tvb, 0, 2,
135                                             "LAPB");
136         lapb_tree = proto_item_add_subtree(ti, ett_lapb);
137         proto_tree_add_uint_format(lapb_tree, hf_lapb_address, tvb, 0, 1, byte0,
138                                        "Address: 0x%02X", byte0);
139     }
140     else
141         lapb_tree = NULL;
142
143     dissect_xdlc_control(tvb, 1, pinfo, lapb_tree, hf_lapb_control,
144             ett_lapb_control, &lapb_cf_items, NULL, NULL, NULL,
145             is_response, FALSE, FALSE);
146
147     /* not end of frame ==> X.25 */
148     if (tvb_reported_length(tvb) > 2) {
149         next_tvb = tvb_new_subset_remaining(tvb, 2);
150         switch (pinfo->p2p_dir) {
151
152         case P2P_DIR_SENT:
153         case P2P_DIR_RECV:
154             call_dissector(x25_dir_handle, next_tvb, pinfo, tree);
155             break;
156
157         default:
158             call_dissector(x25_handle, next_tvb, pinfo, tree);
159             break;
160         }
161     }
162 }
163
164 void
165 proto_register_lapb(void)
166 {
167     static hf_register_info hf[] = {
168         { &hf_lapb_address,
169           { "Address Field", "lapb.address", FT_UINT8, BASE_HEX, NULL, 0x0,
170                 "Address", HFILL }},
171
172         { &hf_lapb_control,
173           { "Control Field", "lapb.control", FT_UINT8, BASE_HEX, NULL, 0x0,
174                 "Control field", HFILL }},
175
176         { &hf_lapb_n_r,
177             { "N(R)", "lapb.control.n_r", FT_UINT8, BASE_DEC,
178               NULL, XDLC_N_R_MASK, NULL, HFILL }},
179
180         { &hf_lapb_n_s,
181             { "N(S)", "lapb.control.n_s", FT_UINT8, BASE_DEC,
182               NULL, XDLC_N_S_MASK, NULL, HFILL }},
183
184         { &hf_lapb_p,
185             { "Poll", "lapb.control.p", FT_BOOLEAN, 8,
186               TFS(&tfs_set_notset), XDLC_P_F, NULL, HFILL }},
187
188         { &hf_lapb_f,
189             { "Final", "lapb.control.f", FT_BOOLEAN, 8,
190               TFS(&tfs_set_notset), XDLC_P_F, NULL, HFILL }},
191
192         { &hf_lapb_s_ftype,
193             { "Supervisory frame type", "lapb.control.s_ftype", FT_UINT8, BASE_HEX,
194               VALS(stype_vals), XDLC_S_FTYPE_MASK, NULL, HFILL }},
195
196         { &hf_lapb_u_modifier_cmd,
197             { "Command", "lapb.control.u_modifier_cmd", FT_UINT8, BASE_HEX,
198               VALS(modifier_vals_cmd), XDLC_U_MODIFIER_MASK, NULL, HFILL }},
199
200         { &hf_lapb_u_modifier_resp,
201             { "Response", "lapb.control.u_modifier_resp", FT_UINT8, BASE_HEX,
202               VALS(modifier_vals_resp), XDLC_U_MODIFIER_MASK, NULL, HFILL }},
203
204         { &hf_lapb_ftype_i,
205             { "Frame type", "lapb.control.ftype", FT_UINT8, BASE_HEX,
206               VALS(ftype_vals), XDLC_I_MASK, NULL, HFILL }},
207
208         { &hf_lapb_ftype_s_u,
209             { "Frame type", "lapb.control.ftype", FT_UINT8, BASE_HEX,
210               VALS(ftype_vals), XDLC_S_U_MASK, NULL, HFILL }},
211     };
212     static gint *ett[] = {
213         &ett_lapb,
214         &ett_lapb_control,
215     };
216
217     proto_lapb = proto_register_protocol("Link Access Procedure Balanced (LAPB)",
218                                          "LAPB", "lapb");
219     proto_register_field_array (proto_lapb, hf, array_length(hf));
220     proto_register_subtree_array(ett, array_length(ett));
221
222     register_dissector("lapb", dissect_lapb, proto_lapb);
223 }
224
225 void
226 proto_reg_handoff_lapb(void)
227 {
228     dissector_handle_t lapb_handle;
229
230     /*
231      * Get handles for the X.25 dissectors; we don't get an X.25
232      * pseudo-header for LAPB-over-Ethernet, but we do get it
233      * for raw LAPB.
234      */
235     x25_dir_handle = find_dissector("x.25_dir");
236     x25_handle = find_dissector("x.25");
237
238     lapb_handle = find_dissector("lapb");
239     dissector_add("wtap_encap", WTAP_ENCAP_LAPB, lapb_handle);
240 }