MSWSP: add two more Property Sets
[wireshark-wip.git] / epan / dissectors / packet-redbackli.c
blob7b01fd66adf57ee039e7f792a2fd8cec6d22da9e
1 /* packet-redbackli.c
3 * $Id$
5 * Redback Lawful Intercept Packet dissector
7 * Copyright 2008 Florian Lohoff <flo[AT]rfc822.org>
9 * Wireshark - Network traffic analyzer
10 * By Gerald Combs <gerald[AT]wireshark.org>
11 * Copyright 1998 Gerald Combs
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 #include "config.h"
30 #include <glib.h>
32 #include <epan/packet.h>
33 #include <epan/addr_resolv.h>
34 #include <epan/strutil.h>
36 static int proto_redbackli = -1;
38 static int hf_redbackli_seqno = -1; /* Sequence No */
39 static int hf_redbackli_liid = -1; /* LI Id */
40 static int hf_redbackli_sessid = -1; /* Session Id */
41 static int hf_redbackli_label = -1; /* Label */
42 static int hf_redbackli_acctid = -1; /* Accounting Session Id */
43 static int hf_redbackli_dir = -1; /* Direction */
44 static int hf_redbackli_eohpad = -1; /* End Of Header Padding */
45 static int hf_redbackli_unknownavp = -1; /* Unknown AVP */
47 static int ett_redbackli = -1;
49 static dissector_handle_t ip_handle;
51 #define RB_AVP_SEQNO 1
52 #define RB_AVP_LIID 2
53 #define RB_AVP_SESSID 3
54 #define RB_AVP_DIR 4
55 #define RB_AVP_LABEL 20
56 #define RB_AVP_ACCTID 40
57 #define RB_AVP_EOH 0
59 static const value_string avp_names[] = {
60 {RB_AVP_SEQNO, "Sequence No"},
61 {RB_AVP_LIID, "Lawful Intercept Id"},
62 {RB_AVP_SESSID, "Session Id"},
63 {RB_AVP_LABEL, "Label"},
64 {RB_AVP_ACCTID, "Accounting Session Id"},
65 {RB_AVP_DIR, "Direction"},
66 {RB_AVP_EOH, "End Of Header"},
67 {0, NULL}
70 static void
71 redbackli_dissect_avp(guint8 avptype, guint8 avplen, tvbuff_t *tvb, gint offset, proto_tree *tree)
73 const char *avpname;
74 proto_tree *ti, *st=NULL;
76 avpname=val_to_str_const(avptype, avp_names, "Unknown");
78 ti = proto_tree_add_text(tree, tvb, offset, avplen+2, "%s AVP", avpname);
79 st = proto_item_add_subtree(ti, ett_redbackli);
81 proto_tree_add_text(st, tvb, offset, 1, "AVP Type: %d", avptype);
82 proto_tree_add_text(st, tvb, offset+1, 1, "AVP Length: %d", avplen);
84 if (!avplen)
85 return;
87 /* XXX: ToDo: Validate the length (avplen) of the fixed length fields
88 before calling proto_tree_add_item().
89 Note that the field lengths have been validated when
90 dissect_avp() is called from redbackli_dissect_heur().
93 switch(avptype) {
94 case(RB_AVP_SEQNO):
95 proto_tree_add_item(st, hf_redbackli_seqno, tvb,
96 offset+2, avplen, ENC_BIG_ENDIAN);
97 break;
98 case(RB_AVP_LIID):
99 proto_tree_add_item(st, hf_redbackli_liid, tvb,
100 offset+2, avplen, ENC_BIG_ENDIAN);
101 break;
102 case(RB_AVP_SESSID):
103 proto_tree_add_item(st, hf_redbackli_sessid, tvb,
104 offset+2, avplen, ENC_BIG_ENDIAN);
105 break;
106 case(RB_AVP_LABEL):
107 proto_tree_add_item(st, hf_redbackli_label, tvb,
108 offset+2, avplen, ENC_ASCII|ENC_NA);
109 break;
110 case(RB_AVP_EOH):
111 proto_tree_add_item(st, hf_redbackli_eohpad, tvb,
112 offset+2, avplen, ENC_NA);
113 break;
114 case(RB_AVP_DIR):
115 proto_tree_add_item(st, hf_redbackli_dir, tvb,
116 offset+2, avplen, ENC_NA);
117 break;
118 case(RB_AVP_ACCTID):
119 proto_tree_add_item(st, hf_redbackli_acctid, tvb,
120 offset+2, avplen, ENC_NA);
121 break;
122 default:
123 proto_tree_add_item(st, hf_redbackli_unknownavp, tvb,
124 offset+2, avplen, ENC_NA);
125 break;
128 return;
131 static void
132 redbackli_dissect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
134 guint8 avptype, avplen;
135 gint len, offset=0;
136 gboolean eoh;
137 proto_tree *ti, *redbackli_tree=NULL;
138 tvbuff_t *next_tvb;
140 col_set_str(pinfo->cinfo,COL_PROTOCOL,"RBLI");
142 if (tree) {
143 ti = proto_tree_add_item(tree, proto_redbackli,
144 tvb, 0, -1, ENC_NA);
145 redbackli_tree = proto_item_add_subtree(ti, ett_redbackli);
148 len=tvb_length(tvb);
149 offset=0;
150 eoh=FALSE;
151 while(!eoh && (len > 2)) {
152 avptype = tvb_get_guint8(tvb, offset+0);
153 avplen = tvb_get_guint8(tvb, offset+1);
155 if ((len-2) < avplen) /* AVP Complete ? */
156 break;
158 if (tree)
159 redbackli_dissect_avp(avptype, avplen, tvb, offset, redbackli_tree);
161 if (avptype == RB_AVP_EOH)
162 eoh=TRUE;
164 offset+=2+avplen;
165 len-=2+avplen;
168 next_tvb = tvb_new_subset_remaining(tvb, offset);
169 call_dissector(ip_handle, next_tvb, pinfo, tree);
173 #define REDBACKLI_INTSIZE 6
174 #define REDBACKLI_EOHSIZE 2
175 #define MIN_REDBACKLI_SIZE (3*REDBACKLI_INTSIZE+REDBACKLI_EOHSIZE)
177 static gboolean
178 redbackli_dissect_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
180 gint len, offset=0;
181 gboolean eoh=FALSE;
182 guint8 avptype, avplen;
183 guint32 avpfound=0;
185 len=tvb_length(tvb);
186 if (len < MIN_REDBACKLI_SIZE)
187 return FALSE;
190 * We scan the possible AVPs and look out for mismatches.
191 * An int AVP needs to be 4 byte long, and the eoh must be 0 or 1
192 * long .. Unknown AVPs also mean not for us ...
195 while((len > 2) && !eoh) {
196 avptype = tvb_get_guint8(tvb, offset+0);
197 avplen = tvb_get_guint8(tvb, offset+1);
199 switch(avptype) {
200 case(RB_AVP_SEQNO):
201 case(RB_AVP_LIID):
202 case(RB_AVP_SESSID):
203 if (avplen != 4)
204 return FALSE;
205 avpfound|=1<<avptype;
206 break;
207 case(RB_AVP_EOH):
208 if (avplen > 1 || offset == 0)
209 return FALSE;
210 eoh=TRUE;
211 break;
212 case(RB_AVP_LABEL):
213 case(RB_AVP_DIR): /* Is this correct? the hf_ originally had FT_UINT8 for DIR */
214 case(RB_AVP_ACCTID):
215 break;
216 default:
217 return FALSE;
219 offset+=2+avplen;
220 len-=2+avplen;
223 if (!(avpfound & (1<<RB_AVP_SEQNO)))
224 return FALSE;
225 if (!(avpfound & (1<<RB_AVP_SESSID)))
226 return FALSE;
227 if (!(avpfound & (1<<RB_AVP_LIID)))
228 return FALSE;
230 redbackli_dissect(tvb, pinfo, tree);
232 return TRUE;
234 void proto_register_redbackli(void) {
235 static hf_register_info hf[] = {
236 { &hf_redbackli_seqno,
237 { "Sequence No", "redbackli.seqno", FT_UINT32, BASE_DEC, NULL, 0x0,
238 NULL, HFILL }},
239 { &hf_redbackli_liid,
240 { "Lawful Intercept Id", "redbackli.liid", FT_UINT32, BASE_DEC, NULL, 0x0,
241 "LI Identifier", HFILL }},
242 { &hf_redbackli_sessid,
243 { "Session Id", "redbackli.sessid", FT_UINT32, BASE_DEC, NULL, 0x0,
244 "Session Identifier", HFILL }},
245 { &hf_redbackli_dir,
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 { "Direction", "redbackli.dir", FT_UINT8, BASE_DEC, NULL, 0x0,
250 #endif
251 { "Direction", "redbackli.dir", FT_BYTES, BASE_NONE, NULL, 0x0,
252 NULL, HFILL }},
253 { &hf_redbackli_label,
254 { "Label", "redbackli.label", FT_STRING, BASE_NONE, NULL, 0x0,
255 NULL, HFILL }},
256 { &hf_redbackli_acctid,
257 { "Acctid", "redbackli.acctid", FT_BYTES, BASE_NONE, NULL, 0x0,
258 NULL, HFILL }},
259 { &hf_redbackli_eohpad,
260 { "End of Header Padding", "redbackli.eohpad", FT_BYTES, BASE_NONE, NULL, 0x0,
261 NULL, HFILL }},
262 { &hf_redbackli_unknownavp,
263 { "Unknown AVP", "redbackli.unknownavp", FT_BYTES, BASE_NONE, NULL, 0x0,
264 NULL, HFILL }}
267 static gint *ett[] = {
268 &ett_redbackli
271 proto_redbackli = proto_register_protocol("Redback Lawful Intercept",
272 "RedbackLI","redbackli");
274 proto_register_field_array(proto_redbackli,hf,array_length(hf));
275 proto_register_subtree_array(ett,array_length(ett));
277 register_dissector("redbackli", redbackli_dissect, proto_redbackli);
280 void proto_reg_handoff_redbackli(void) {
281 dissector_handle_t redbackli_handle;
283 ip_handle = find_dissector("ip");
285 redbackli_handle = find_dissector("redbackli");
286 dissector_add_handle("udp.port", redbackli_handle); /* for 'decode-as' */
288 heur_dissector_add("udp", redbackli_dissect_heur, proto_redbackli);