change a whole bunch of ethereal into wireshark
[obnox/wireshark/wip.git] / epan / dissectors / packet-isdn.c
1 /* packet-isdn.c
2  * Routines for ISDN packet disassembly
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #include <stdio.h>
30 #include <glib.h>
31 #include <epan/packet.h>
32 #include <epan/circuit.h>
33
34 static int proto_isdn = -1;
35 static int hf_isdn_channel = -1;
36
37 static gint ett_isdn = -1;
38
39 static dissector_handle_t lapd_handle;
40 static dissector_handle_t ppp_hdlc_handle;
41 static dissector_handle_t v120_handle;
42 static dissector_handle_t data_handle;
43
44 static const value_string channel_vals[] = {
45         { 0,    "D" },
46         { 1,    "B1" },
47         { 2,    "B2" },
48         { 3,    "B3" },
49         { 4,    "B4" },
50         { 5,    "B5" },
51         { 6,    "B6" },
52         { 7,    "B7" },
53         { 8,    "B8" },
54         { 9,    "B9" },
55         { 10,   "B10" },
56         { 11,   "B11" },
57         { 12,   "B12" },
58         { 13,   "B13" },
59         { 14,   "B14" },
60         { 15,   "B15" },
61         { 16,   "B16" },
62         { 17,   "B17" },
63         { 18,   "B19" },
64         { 19,   "B19" },
65         { 20,   "B20" },
66         { 21,   "B21" },
67         { 22,   "B22" },
68         { 23,   "B23" },
69         { 24,   "B24" },
70         { 25,   "B25" },
71         { 26,   "B26" },
72         { 27,   "B27" },
73         { 28,   "B29" },
74         { 29,   "B29" },
75         { 30,   "B30" },
76         { 0,    NULL }
77 };
78
79 static void
80 dissect_isdn(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
81 {
82         proto_tree *isdn_tree;
83         proto_item *ti;
84         static const guint8 v120_sabme[3] = { 0x08, 0x01, 0x7F };
85         static const guint8 ppp[2] = { 0xFF, 0x03 };
86         circuit_t *circuit;
87
88         if (check_col(pinfo->cinfo, COL_PROTOCOL))
89                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "ISDN");
90
91         if (pinfo->pseudo_header->isdn.uton) {
92                 if (check_col(pinfo->cinfo, COL_RES_DL_DST))
93                         col_set_str(pinfo->cinfo, COL_RES_DL_DST, "Network");
94                 if (check_col(pinfo->cinfo, COL_RES_DL_SRC))
95                         col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "User");
96         } else {
97                 if (check_col(pinfo->cinfo, COL_RES_DL_DST))
98                     col_set_str(pinfo->cinfo, COL_RES_DL_DST, "User");
99                 if (check_col(pinfo->cinfo, COL_RES_DL_SRC))
100                     col_set_str(pinfo->cinfo, COL_RES_DL_SRC, "Network");
101         }
102
103         pinfo->ctype = CT_ISDN;
104         pinfo->circuit_id = pinfo->pseudo_header->isdn.channel;
105
106         if (tree) {
107                 ti = proto_tree_add_item(tree, proto_isdn, tvb, 0, 0, FALSE);
108                 isdn_tree = proto_item_add_subtree(ti, ett_isdn);
109
110                 proto_tree_add_uint(isdn_tree, hf_isdn_channel, tvb, 0, 0,
111                     pinfo->pseudo_header->isdn.channel);
112         }
113
114         /*
115          * Set up a circuit for this channel, and assign it a dissector.
116          */
117         circuit = find_circuit(pinfo->ctype, pinfo->circuit_id, pinfo->fd->num);
118         if (circuit == NULL)
119                 circuit = circuit_new(pinfo->ctype, pinfo->circuit_id,
120                     pinfo->fd->num);
121
122         if (circuit_get_dissector(circuit) == NULL) {
123                 /*
124                  * We don't yet know the type of traffic on the circuit.
125                  */
126                 switch (pinfo->pseudo_header->isdn.channel) {
127
128                 case 0:
129                         /*
130                          * D-channel.  Treat it as LAPD.
131                          */
132                         circuit_set_dissector(circuit, lapd_handle);
133                         break;
134
135                 default:
136                         /*
137                          * B-channel.
138                          *
139                          * We don't know yet whether the datastream is
140                          * V.120 or not; this heuristic tries to figure
141                          * that out.
142                          *
143                          * We cannot glean this from the Q.931 SETUP message,
144                          * because no commercial V.120 implementation I've
145                          * seen actually sets the V.120 protocol discriminator
146                          * (that, or I'm misreading the spec badly).
147                          *
148                          * TODO: close the circuit after a close on the B
149                          * channel is detected.
150                          *
151                          *      -Bert Driehuis (from the i4btrace reader;
152                          *       this heuristic was moved from there to
153                          *       here)
154                          *
155                          * XXX - I don't know that one can guarantee that
156                          * the SABME will appear in the first frame on
157                          * the channels, so we probably can't just say
158                          * "it must be PPP" if we don't immediately see
159                          * the V.120 SABME frame, so we do so only if
160                          * we see the 0xFF 0x03.  Unfortunately, that
161                          * won't do the right thing if the PPP-over-HDLC
162                          * headers aren't being used....
163                          */
164                         if (tvb_memeql(tvb, 0, v120_sabme, 3) == 0) {
165                                 /*
166                                  * We assume this is V.120.
167                                  */
168                                 circuit_set_dissector(circuit, v120_handle);
169                         } else if (tvb_memeql(tvb, 0, ppp, 2) == 0) {
170                                 /*
171                                  * We assume this is PPP.
172                                  */
173                                 circuit_set_dissector(circuit, ppp_hdlc_handle);
174                         }
175                         break;
176                 }
177         }
178
179         if (!try_circuit_dissector(pinfo->ctype, pinfo->circuit_id,
180             pinfo->fd->num, tvb, pinfo, tree))
181                 call_dissector(data_handle, tvb, pinfo, tree);
182 }
183
184 void
185 proto_register_isdn(void)
186 {
187         static hf_register_info hf[] = {
188                 { &hf_isdn_channel,
189                 { "Channel",    "isdn.channel", FT_UINT8, BASE_DEC,
190                   VALS(channel_vals), 0x0, "", HFILL }},
191         };
192         static gint *ett[] = {
193                 &ett_isdn,
194         };
195         proto_isdn = proto_register_protocol("ISDN", "ISDN", "isdn");
196         proto_register_field_array(proto_isdn, hf, array_length(hf));
197         proto_register_subtree_array(ett, array_length(ett));
198 }
199
200 void
201 proto_reg_handoff_isdn(void)
202 {
203         dissector_handle_t isdn_handle;
204
205         /*
206          * Get handles for the LAPD, PPP, and V.120 dissectors.
207          */
208         lapd_handle = find_dissector("lapd");
209         ppp_hdlc_handle = find_dissector("ppp_hdlc");
210         v120_handle = find_dissector("v120");
211         data_handle = find_dissector("data");
212
213         isdn_handle = create_dissector_handle(dissect_isdn, proto_isdn);
214
215         dissector_add("wtap_encap", WTAP_ENCAP_ISDN, isdn_handle);
216 }