Don't guard col_set_str (COL_PROTOCOL) with col_check
[obnox/wireshark/wip.git] / epan / dissectors / packet-kismet.c
1 /* packet-kismet.c
2  * Routines for kismet packet dissection
3  * Copyright 2006, Krzysztof Burghardt <krzysztof@burghardt.pl>
4  *
5  * $Id$
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1998 Gerald Combs
10  *
11  * Copied from packet-pop.c
12  *
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.
17  *
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.
22  *
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <stdio.h>
33
34 #include <string.h>
35 #include <glib.h>
36 #include <epan/packet.h>
37 #include <epan/strutil.h>
38 #include <epan/prefs.h>
39
40 static int proto_kismet = -1;
41 static int hf_kismet_response = -1;
42 static int hf_kismet_request = -1;
43
44 static gint ett_kismet = -1;
45 static gint ett_kismet_reqresp = -1;
46
47 static dissector_handle_t data_handle;
48
49 #define TCP_PORT_KISMET 2501
50
51 static guint global_kismet_tcp_port = TCP_PORT_KISMET;
52
53 static gboolean response_is_continuation(const guchar * data);
54 void proto_reg_handoff_kismet(void);
55 void proto_register_kismet(void);
56
57 static gboolean
58 dissect_kismet(tvbuff_t * tvb, packet_info * pinfo, proto_tree * tree)
59 {
60         gboolean is_request;
61         gboolean is_continuation;
62         proto_tree *kismet_tree=NULL, *reqresp_tree=NULL;
63         proto_item *ti;
64         proto_item *tmp_item;
65         gint offset = 0;
66         const guchar *line;
67         gint next_offset;
68         int linelen;
69         int tokenlen;
70         int i;
71         const guchar *next_token;
72
73         /*
74          * Find the end of the first line.
75          *
76          * Note that "tvb_find_line_end()" will return a value that is
77          * not longer than what's in the buffer, so the "tvb_get_ptr()"
78          * call won't throw an exception.
79          */
80         linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
81         line = tvb_get_ptr(tvb, offset, linelen);
82
83         /*
84          * Check if it is an ASCII based protocol with reasonable length
85          * packets, if not return, and try annother dissector.
86          */
87         if (linelen < 8) {
88                 /*
89                  * Packet is too short
90                  */
91                 return FALSE;
92         } else {
93                 for (i = 0; i < 8; ++i) {
94                         /*
95                          * Packet contains non-ASCII data
96                          */
97                         if (line[i] < 32 || line[i] > 128)
98                                 return FALSE;
99                 }
100         }
101
102         /*
103          * If it is Kismet traffic set COL_PROTOCOL.
104          */
105         col_set_str(pinfo->cinfo, COL_PROTOCOL, "kismet");
106
107         /*
108          * Check if it is request, reply or continuation.
109          */
110         if (pinfo->match_port == pinfo->destport) {
111                 is_request = TRUE;
112                 is_continuation = FALSE;
113         } else {
114                 is_request = FALSE;
115                 is_continuation = response_is_continuation (line);
116         }
117
118         if (check_col(pinfo->cinfo, COL_INFO)) {
119                 /*
120                  * Put the first line from the buffer into the summary
121                  * if it's a kismet request or reply (but leave out the
122                  * line terminator).
123                  * Otherwise, just call it a continuation.
124                  */
125                 if (is_continuation)
126                         col_set_str(pinfo->cinfo, COL_INFO, "Continuation");
127                 else
128                         col_add_fstr(pinfo->cinfo, COL_INFO, "%s: %s",
129                                 is_request ? "Request" : "Response",
130                                 format_text(line, linelen));
131         }
132
133         if (tree) {
134                 ti = proto_tree_add_item(tree, proto_kismet, tvb, offset, -1, FALSE);
135                 kismet_tree = proto_item_add_subtree(ti, ett_kismet);
136         }
137
138         if (is_continuation) {
139                 /*
140                  * Put the whole packet into the tree as data.
141                  */
142                 call_dissector(data_handle, tvb, pinfo, kismet_tree);
143                 return TRUE;
144         }
145
146         if (is_request) {
147                 tmp_item = proto_tree_add_boolean(kismet_tree,
148                                 hf_kismet_request, tvb, 0, 0, TRUE);
149         } else {
150                 tmp_item = proto_tree_add_boolean(kismet_tree,
151                                 hf_kismet_response, tvb, 0, 0, TRUE);
152         }
153         PROTO_ITEM_SET_GENERATED (tmp_item);
154
155         while (tvb_offset_exists(tvb, offset)) {
156                 /*
157                  * Find the end of the line.
158                  */
159                 linelen = tvb_find_line_end(tvb, offset, -1, &next_offset, FALSE);
160
161                 if (linelen) {
162                         /*
163                          * Put this line.
164                          */
165                         ti = proto_tree_add_text(kismet_tree, tvb, offset,
166                                         next_offset - offset, "%s",
167                                         tvb_format_text(tvb, offset,
168                                         next_offset - offset - 1));
169                         reqresp_tree = proto_item_add_subtree(ti, ett_kismet_reqresp);
170                         tokenlen = get_token_len(line, line + linelen, &next_token);
171                         if (tokenlen != 0) {
172                                 guint8 *reqresp;
173                                 reqresp = tvb_get_ephemeral_string(tvb, offset, tokenlen);
174                                 if (is_request) {
175                                         /*
176                                          * No request dissection
177                                          */
178                                 } else {
179                                         /*
180                                          * *KISMET: {Version} {Start time} \001{Server name}\001 {Build Revision}
181                                          * two fields left undocumented: {???} {?ExtendedVersion?}
182                                          */
183                                         if (!strncmp(reqresp, "*KISMET", 7)) {
184                                                 offset += (gint) (next_token - line);
185                                                 linelen -= (int) (next_token - line);
186                                                 line = next_token;
187                                                 tokenlen = get_token_len(line, line + linelen, &next_token);
188                                                 proto_tree_add_text(reqresp_tree, tvb, offset,
189                                                         tokenlen, "Kismet version: %s",
190                                                         format_text(line, tokenlen));
191
192                                                 offset += (gint) (next_token - line);
193                                                 linelen -= (int) (next_token - line);
194                                                 line = next_token;
195                                                 tokenlen = get_token_len(line, line + linelen, &next_token);
196                                                 proto_tree_add_text(reqresp_tree, tvb, offset,
197                                                         tokenlen, "Start time: %s",
198                                                         format_text(line, tokenlen));
199
200                                                 offset += (gint) (next_token - line);
201                                                 linelen -= (int) (next_token - line);
202                                                 line = next_token;
203                                                 tokenlen = get_token_len(line, line + linelen, &next_token);
204                                                 proto_tree_add_text(reqresp_tree, tvb, offset,
205                                                         tokenlen, "Server name: %s",
206                                                         format_text(line + 1, tokenlen - 2));
207
208                                                 offset += (gint) (next_token - line);
209                                                 linelen -= (int) (next_token - line);
210                                                 line = next_token;
211                                                 tokenlen = get_token_len(line, line + linelen, &next_token);
212                                                 proto_tree_add_text(reqresp_tree, tvb, offset,
213                                                         tokenlen, "Build revision: %s",
214                                                         format_text(line, tokenlen));
215
216                                                 offset += (gint) (next_token - line);
217                                                 linelen -= (int) (next_token - line);
218                                                 line = next_token;
219                                                 tokenlen = get_token_len(line, line + linelen, &next_token);
220                                                 proto_tree_add_text(reqresp_tree, tvb, offset,
221                                                         tokenlen, "Unknown field: %s",
222                                                         format_text(line, tokenlen));
223
224                                                 offset += (gint) (next_token - line);
225                                                 linelen -= (int) (next_token - line);
226                                                 line = next_token;
227                                                 tokenlen = get_token_len(line, line + linelen, &next_token);
228                                                 proto_tree_add_text(reqresp_tree, tvb, offset,
229                                                         tokenlen,
230                                                         "Extended version string: %s",
231                                                         format_text(line, tokenlen));
232                                         }
233                                         /*
234                                          * *TIME: {Time}
235                                          */
236                                         if (!strncmp(reqresp, "*TIME", 5)) {
237                                                 time_t t;
238                                                 char *ptr;
239
240                                                 offset += (gint) (next_token - line);
241                                                 linelen -= (int) (next_token - line);
242                                                 line = next_token;
243                                                 tokenlen = get_token_len(line, line + linelen, &next_token);
244
245                                                 /*
246                                                  * Convert form ascii to time_t
247                                                  */
248                                                 t = atoi(format_text (line, tokenlen));
249
250                                                 /*
251                                                  * Format ascii representaion of time
252                                                  */
253                                                 ptr = ctime(&t);
254                                                 /*
255                                                  * Delete final '\n'
256                                                  */
257                                                 ptr[strlen(ptr) - 1] = 0;
258
259                                                 proto_tree_add_text(reqresp_tree, tvb, offset,
260                                                         tokenlen, "Time: %s", ptr);
261                                         }
262                                 }
263
264                                 offset += (gint) (next_token - line);
265                                 linelen -= (int) (next_token - line);
266                                 line = next_token;
267                         }
268                 }
269                 offset = next_offset;
270         }
271   
272         return TRUE;
273 }
274
275 static gboolean
276 response_is_continuation(const guchar * data)
277 {
278         if (!strncmp(data, "*", 1))
279                 return FALSE;
280
281         if (!strncmp(data, "!", 1))
282                 return FALSE;
283
284         return TRUE;
285 }
286
287 void
288 proto_register_kismet(void)
289 {
290         static hf_register_info hf[] = {
291                 {&hf_kismet_response,
292                 {"Response", "kismet.response", FT_BOOLEAN, BASE_NONE, 
293                 NULL, 0x0, "TRUE if kismet response", HFILL}},
294
295                 {&hf_kismet_request,
296                 {"Request", "kismet.request", FT_BOOLEAN, BASE_NONE, 
297                 NULL, 0x0, "TRUE if kismet request", HFILL}}
298         };
299
300         static gint *ett[] = {
301                 &ett_kismet,
302                 &ett_kismet_reqresp,
303         };
304         module_t *kismet_module;
305
306         proto_kismet = proto_register_protocol("Kismet Client/Server Protocol", "Kismet", "kismet");
307         proto_register_field_array(proto_kismet, hf, array_length (hf));
308         proto_register_subtree_array(ett, array_length (ett));
309
310         /* Register our configuration options for Kismet, particularly our port */
311
312         kismet_module = prefs_register_protocol(proto_kismet, proto_reg_handoff_kismet);
313
314         prefs_register_uint_preference(kismet_module, "tcp.port",
315                           "Kismet Server TCP Port",
316                           "Set the port for Kismet Client/Server messages (if other"
317                           " than the default of 2501)", 10,
318                           &global_kismet_tcp_port);
319 }
320
321 void
322 proto_reg_handoff_kismet(void)
323 {
324         static gboolean kismet_prefs_initialized = FALSE;
325         static dissector_handle_t kismet_handle;
326         static guint tcp_port;
327
328         if (!kismet_prefs_initialized) {
329                 kismet_handle = new_create_dissector_handle(dissect_kismet, proto_kismet);
330                 data_handle = find_dissector("data");
331                 kismet_prefs_initialized = TRUE;
332         } else {
333                 dissector_delete("tcp.port", tcp_port, kismet_handle);
334         }
335
336         /* Set our port number for future use */
337         tcp_port = global_kismet_tcp_port;
338
339         dissector_add("tcp.port", global_kismet_tcp_port, kismet_handle);
340 }