Fixup: tvb_get_string(z) -> tvb_get_string(z)_enc
[metze/wireshark/wip.git] / epan / dissectors / packet-redbackli.c
1 /* packet-redbackli.c
2  *
3  * Redback Lawful Intercept Packet dissector
4  *
5  * Copyright 2008 Florian Lohoff <flo[AT]rfc822.org>
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald[AT]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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include "config.h"
27
28 #include <glib.h>
29
30 #include <epan/packet.h>
31 #include <epan/addr_resolv.h>
32 #include <epan/strutil.h>
33
34 void proto_register_redbackli(void);
35 void proto_reg_handoff_redbackli(void);
36
37 static int proto_redbackli = -1;
38
39 static int hf_redbackli_seqno = -1;             /* Sequence No */
40 static int hf_redbackli_liid = -1;              /* LI Id */
41 static int hf_redbackli_sessid = -1;            /* Session Id */
42 static int hf_redbackli_label = -1;             /* Label */
43 static int hf_redbackli_acctid = -1;            /* Accounting Session Id */
44 static int hf_redbackli_dir = -1;               /* Direction */
45 static int hf_redbackli_eohpad = -1;            /* End Of Header Padding */
46 static int hf_redbackli_unknownavp = -1;        /* Unknown AVP */
47
48 static int ett_redbackli = -1;
49
50 static dissector_handle_t ip_handle;
51
52 #define RB_AVP_SEQNO    1
53 #define RB_AVP_LIID     2
54 #define RB_AVP_SESSID   3
55 #define RB_AVP_DIR      4
56 #define RB_AVP_LABEL    20
57 #define RB_AVP_ACCTID   40
58 #define RB_AVP_EOH      0
59
60 static const value_string avp_names[] = {
61         {RB_AVP_SEQNO,          "Sequence No"},
62         {RB_AVP_LIID,           "Lawful Intercept Id"},
63         {RB_AVP_SESSID,         "Session Id"},
64         {RB_AVP_LABEL,          "Label"},
65         {RB_AVP_ACCTID,         "Accounting Session Id"},
66         {RB_AVP_DIR,            "Direction"},
67         {RB_AVP_EOH,            "End Of Header"},
68         {0,                     NULL}
69 };
70
71 static void
72 redbackli_dissect_avp(guint8 avptype, guint8 avplen, tvbuff_t *tvb, gint offset, proto_tree *tree)
73 {
74         const char      *avpname;
75         proto_tree      *ti, *st = NULL;
76
77         avpname = val_to_str_const(avptype, avp_names, "Unknown");
78
79         ti = proto_tree_add_text(tree, tvb, offset, avplen+2, "%s AVP", avpname);
80         st = proto_item_add_subtree(ti, ett_redbackli);
81
82         proto_tree_add_text(st, tvb, offset, 1, "AVP Type: %d", avptype);
83         proto_tree_add_text(st, tvb, offset+1, 1, "AVP Length: %d", avplen);
84
85         if (!avplen)
86                 return;
87
88         /* XXX: ToDo: Validate the length (avplen) of the fixed length fields
89            before calling proto_tree_add_item().
90            Note that the field lengths have been validated when
91            dissect_avp() is called from redbackli_dissect_heur().
92         */
93
94         switch (avptype) {
95                 case(RB_AVP_SEQNO):
96                         proto_tree_add_item(st, hf_redbackli_seqno, tvb,
97                                             offset+2, avplen, ENC_BIG_ENDIAN);
98                         break;
99                 case(RB_AVP_LIID):
100                         proto_tree_add_item(st, hf_redbackli_liid, tvb,
101                                             offset+2, avplen, ENC_BIG_ENDIAN);
102                         break;
103                 case(RB_AVP_SESSID):
104                         proto_tree_add_item(st, hf_redbackli_sessid, tvb,
105                                             offset+2, avplen, ENC_BIG_ENDIAN);
106                         break;
107                 case(RB_AVP_LABEL):
108                         proto_tree_add_item(st, hf_redbackli_label, tvb,
109                                             offset+2, avplen, ENC_ASCII|ENC_NA);
110                         break;
111                 case(RB_AVP_EOH):
112                         proto_tree_add_item(st, hf_redbackli_eohpad, tvb,
113                                             offset+2, avplen, ENC_NA);
114                         break;
115                 case(RB_AVP_DIR):
116                         proto_tree_add_item(st, hf_redbackli_dir, tvb,
117                                         offset+2, avplen, ENC_NA);
118                         break;
119                 case(RB_AVP_ACCTID):
120                         proto_tree_add_item(st, hf_redbackli_acctid, tvb,
121                                             offset+2, avplen, ENC_NA);
122                         break;
123                 default:
124                         proto_tree_add_item(st, hf_redbackli_unknownavp, tvb,
125                                             offset+2, avplen, ENC_NA);
126                         break;
127         }
128
129         return;
130 }
131
132 static void
133 redbackli_dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
134 {
135         guint8          avptype, avplen;
136         gint            len, offset = 0;
137         gboolean        eoh;
138         proto_tree      *ti, *redbackli_tree = NULL;
139         tvbuff_t        *next_tvb;
140
141         col_set_str(pinfo->cinfo, COL_PROTOCOL, "RBLI");
142
143         if (tree) {
144                 ti = proto_tree_add_item(tree, proto_redbackli,
145                                          tvb, 0, -1, ENC_NA);
146                 redbackli_tree = proto_item_add_subtree(ti, ett_redbackli);
147         }
148
149         len = tvb_length(tvb);
150         offset = 0;
151         eoh = FALSE;
152         while (!eoh && (len > 2)) {
153                 avptype = tvb_get_guint8(tvb, offset+0);
154                 avplen = tvb_get_guint8(tvb, offset+1);
155
156                 if ((len-2) < avplen)           /* AVP Complete ? */
157                         break;
158
159                 if (tree)
160                         redbackli_dissect_avp(avptype, avplen, tvb, offset, redbackli_tree);
161
162                 if (avptype == RB_AVP_EOH)
163                         eoh = TRUE;
164
165                 offset += 2 + avplen;
166                 len    -= 2 + avplen;
167         }
168
169         next_tvb = tvb_new_subset_remaining(tvb, offset);
170         call_dissector(ip_handle, next_tvb, pinfo, tree);
171 }
172
173
174 #define REDBACKLI_INTSIZE       6
175 #define REDBACKLI_EOHSIZE       2
176 #define MIN_REDBACKLI_SIZE      (3*REDBACKLI_INTSIZE+REDBACKLI_EOHSIZE)
177
178 static gboolean
179 redbackli_dissect_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
180 {
181         gint            len, offset = 0;
182         gboolean        eoh = FALSE;
183         guint8          avptype, avplen;
184         guint32         avpfound = 0;
185
186         len = tvb_length(tvb);
187         if (len < MIN_REDBACKLI_SIZE)
188                 return FALSE;
189
190         /*
191          * We scan the possible AVPs and look out for mismatches.
192          * An int AVP needs to be 4 byte long, and the eoh must be 0 or 1
193          * long .. Unknown AVPs also mean not for us ...
194          *
195          */
196         while ((len > 2) && !eoh) {
197                 avptype = tvb_get_guint8(tvb, offset+0);
198                 avplen = tvb_get_guint8(tvb, offset+1);
199
200                 switch (avptype) {
201                         case(RB_AVP_SEQNO):
202                         case(RB_AVP_LIID):
203                         case(RB_AVP_SESSID):
204                                 if (avplen != 4)
205                                         return FALSE;
206                                 avpfound |= 1<<avptype;
207                                 break;
208                         case(RB_AVP_EOH):
209                                 if (avplen > 1 || offset == 0)
210                                         return FALSE;
211                                 eoh = TRUE;
212                                 break;
213                         case(RB_AVP_LABEL):
214                         case(RB_AVP_DIR):   /* Is this correct? the hf_ originally had FT_UINT8 for DIR */
215                         case(RB_AVP_ACCTID):
216                                 break;
217                         default:
218                                 return FALSE;
219                 }
220                 offset += 2 + avplen;
221                 len    -= 2 + avplen;
222         }
223
224         if (!(avpfound & (1<<RB_AVP_SEQNO)))
225                 return FALSE;
226         if (!(avpfound & (1<<RB_AVP_SESSID)))
227                 return FALSE;
228         if (!(avpfound & (1<<RB_AVP_LIID)))
229                 return FALSE;
230
231         redbackli_dissect(tvb, pinfo, tree);
232
233         return TRUE;
234 }
235 void proto_register_redbackli(void) {
236         static hf_register_info hf[] = {
237                 { &hf_redbackli_seqno,
238                         { "Sequence No", "redbackli.seqno", FT_UINT32, BASE_DEC, NULL, 0x0,
239                         NULL, HFILL }},
240                 { &hf_redbackli_liid,
241                         { "Lawful Intercept Id", "redbackli.liid", FT_UINT32, BASE_DEC, NULL, 0x0,
242                         "LI Identifier", HFILL }},
243                 { &hf_redbackli_sessid,
244                         { "Session Id", "redbackli.sessid", FT_UINT32, BASE_DEC, NULL, 0x0,
245                         "Session Identifier", HFILL }},
246 #if 0 /* XXX: If one goes by the heuristic then this field can be variable length ??
247          In the absence of any documentation We'll assume that's the case
248          (even though 'direction' sounds like a fixed length field */
249                 { &hf_redbackli_dir,
250                         { "Direction", "redbackli.dir", FT_UINT8, BASE_DEC, NULL, 0x0,
251                         NULL, HFILL }},
252 #else
253                 { &hf_redbackli_dir,
254                         { "Direction", "redbackli.dir", FT_BYTES, BASE_NONE, NULL, 0x0,
255                         NULL, HFILL }},
256 #endif
257                 { &hf_redbackli_label,
258                         { "Label", "redbackli.label", FT_STRING, BASE_NONE, NULL, 0x0,
259                         NULL, HFILL }},
260                 { &hf_redbackli_acctid,
261                         { "Acctid", "redbackli.acctid", FT_BYTES, BASE_NONE, NULL, 0x0,
262                         NULL, HFILL }},
263                 { &hf_redbackli_eohpad,
264                         { "End of Header Padding", "redbackli.eohpad", FT_BYTES, BASE_NONE, NULL, 0x0,
265                         NULL, HFILL }},
266                 { &hf_redbackli_unknownavp,
267                         { "Unknown AVP", "redbackli.unknownavp", FT_BYTES, BASE_NONE, NULL, 0x0,
268                         NULL, HFILL }}
269                 };
270
271         static gint *ett[] = {
272                 &ett_redbackli
273         };
274
275         proto_redbackli = proto_register_protocol("Redback Lawful Intercept",
276                                                   "RedbackLI", "redbackli");
277
278         proto_register_field_array(proto_redbackli, hf, array_length(hf));
279         proto_register_subtree_array(ett, array_length(ett));
280
281         register_dissector("redbackli", redbackli_dissect, proto_redbackli);
282 }
283
284 void proto_reg_handoff_redbackli(void) {
285         dissector_handle_t redbackli_handle;
286
287         ip_handle = find_dissector("ip");
288
289         redbackli_handle = find_dissector("redbackli");
290         dissector_add_handle("udp.port", redbackli_handle);  /* for 'decode-as' */
291
292         heur_dissector_add("udp", redbackli_dissect_heur, proto_redbackli);
293 }
294
295
296 /*
297  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
298  *
299  * Local variables:
300  * c-basic-offset: 8
301  * tab-width: 8
302  * indent-tabs-mode: t
303  * End:
304  *
305  * vi: set shiftwidth=8 tabstop=8 noexpandtab:
306  * :indentSize=8:tabSize=8:noTabs=false:
307  */