From Didier Gautheron:
[obnox/wireshark/wip.git] / epan / dissectors / packet-tivoconnect.c
1 /* packet-tivoconnect.c
2  * Routines for TiVoConnect Discovery Protocol dissection
3  * Copyright 2006, Kees Cook <kees@outflux.net>
4  * IANA UDP/TCP port: 2190 (tivoconnect)
5  * Protocol Spec: http://tivo.com/developer/i/TiVoConnectDiscovery.pdf
6  *
7  * IANA's full name is "TiVoConnect Beacon", where as TiVo's own
8  * documentation calls this protocol "TiVoConnect Discovery Protocol".
9  *
10  * $Id$
11  *
12  * Wireshark - Network traffic analyzer
13  * By Gerald Combs <gerald@wireshark.org>
14  * Copyright 1998 Gerald Combs
15  *
16  * Copied from README.developer
17  * 
18  * This program is free software; you can redistribute it and/or
19  * modify it under the terms of the GNU General Public License
20  * as published by the Free Software Foundation; either version 2
21  * of the License, or (at your option) any later version.
22  * 
23  * This program is distributed in the hope that it will be useful,
24  * but WITHOUT ANY WARRANTY; without even the implied warranty of
25  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  * GNU General Public License for more details.
27  * 
28  * You should have received a copy of the GNU General Public License
29  * along with this program; if not, write to the Free Software
30  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31  */
32
33 /*
34  * TODO
35  * - split services into a subtree
36  * - split platform into a subtree
37  *
38  */
39
40 #ifdef HAVE_CONFIG_H
41 # include "config.h"
42 #endif
43
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47
48 #include <glib.h>
49
50 #include <epan/packet.h>
51 #include <epan/ipproto.h>
52
53 /* Forward declaration we need below */
54 void proto_reg_handoff_tivoconnect(void);
55
56 /* Initialize the protocol and registered fields */
57 static int proto_tivoconnect = -1;
58 static int hf_tivoconnect_flavor = -1;
59 static int hf_tivoconnect_method = -1;
60 static int hf_tivoconnect_platform = -1;
61 static int hf_tivoconnect_machine = -1;
62 static int hf_tivoconnect_identity = -1;
63 static int hf_tivoconnect_services = -1;
64 static int hf_tivoconnect_version = -1;
65
66 /* Initialize the subtree pointers */
67 static gint ett_tivoconnect = -1;
68
69 /* Code to actually dissect the packets */
70 static int
71 dissect_tivoconnect(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
72 {
73     /* parsing variables */
74     gchar * string = NULL;
75     gint length = -1;
76     /* value strings */
77     gchar * proto_name = NULL;
78     gchar * packet_identity = NULL;
79     gchar * packet_machine = NULL;
80
81     /* validate that we have a tivoconnect packet */
82     if ( tvb_strncaseeql(tvb, 0, "tivoconnect", 11) != 0) {
83         return 0;
84     }
85
86     length = tvb_length(tvb);
87     string = (gchar*)tvb_get_ephemeral_string(tvb, 0, length);
88
89     /* Make entries in Protocol column and Info column on summary display */
90     col_set_str(pinfo->cinfo, COL_PROTOCOL, "TiVoConnect");
91     
92     /* make a distinction between UDP and TCP packets */
93     proto_name = pinfo->ipproto == IP_PROTO_TCP ?
94                     "Discovery Connection" :
95                     "Discovery Beacon";
96
97     col_set_str(pinfo->cinfo, COL_INFO, proto_name);
98
99     if (tree) {
100         /* Set up structures needed to add the protocol subtree and manage it */
101         proto_item *ti = NULL;
102         proto_tree *tivoconnect_tree = NULL;
103
104         /* parsing variables */
105         guint offset = 0;
106         gchar * field = NULL;
107
108         /* create display subtree for the protocol */
109         ti = proto_tree_add_item(tree, proto_tivoconnect, tvb, 0, -1, FALSE);
110
111         tivoconnect_tree = proto_item_add_subtree(ti, ett_tivoconnect);
112
113         /* process the packet */
114         for ( field = strtok(string,"\n");
115               field;
116               offset+=length, field = strtok(NULL,"\n") ) {
117             gchar * value = NULL;
118             gint fieldlen;
119
120             length = (int)strlen(field) + 1;
121
122             if ( !(value=strchr(field, '=')) ) {
123                 /* bad packet: missing the field separator */
124                 continue;
125             }
126             *value++='\0';
127             fieldlen=(int)strlen(field)+1;
128
129             if ( g_ascii_strcasecmp(field,"tivoconnect") == 0 ) {
130                 proto_tree_add_item(tivoconnect_tree,
131                     hf_tivoconnect_flavor, tvb, offset+fieldlen,
132                     length-fieldlen-1, FALSE);
133             }
134             else if ( g_ascii_strcasecmp(field,"method") == 0 ) {
135                 proto_tree_add_item(tivoconnect_tree,
136                     hf_tivoconnect_method, tvb, offset+fieldlen,
137                     length-fieldlen-1, FALSE);
138             }
139             else if ( g_ascii_strcasecmp(field,"platform") == 0 ) {
140                 proto_tree_add_item(tivoconnect_tree,
141                     hf_tivoconnect_platform, tvb, offset+fieldlen,
142                     length-fieldlen-1, FALSE);
143             }
144             else if ( g_ascii_strcasecmp(field,"machine") == 0 ) {
145                 proto_tree_add_item(tivoconnect_tree,
146                     hf_tivoconnect_machine, tvb, offset+fieldlen,
147                     length-fieldlen-1, FALSE);
148                 packet_machine = value;
149             }
150             else if ( g_ascii_strcasecmp(field,"identity") == 0 ) {
151                 proto_tree_add_item(tivoconnect_tree,
152                     hf_tivoconnect_identity, tvb, offset+fieldlen,
153                     length-fieldlen-1, FALSE);
154                 packet_identity = value;
155             }
156             else if ( g_ascii_strcasecmp(field,"services") == 0 ) {
157                 proto_tree_add_item(tivoconnect_tree,
158                     hf_tivoconnect_services, tvb, offset+fieldlen,
159                     length-fieldlen-1, FALSE);
160             }
161             else if ( g_ascii_strcasecmp(field,"swversion") == 0 ) {
162                 proto_tree_add_item(tivoconnect_tree,
163                     hf_tivoconnect_version, tvb, offset+fieldlen,
164                     length-fieldlen-1, FALSE);
165             }
166             else {
167                 /* unknown field! */
168             }
169         }
170
171         /* Adjust "Info" column and top of tree into more useful info */
172         if (packet_machine) {
173             proto_item_append_text(ti, ", %s", packet_machine);
174             if (check_col(pinfo->cinfo, COL_INFO)) 
175                 col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s",
176                                             proto_name, packet_machine);
177         }
178         if (packet_identity) {
179             proto_item_append_text(ti,
180                         packet_machine ? " (%s)" : ", ID:%s",
181                         packet_identity);
182             if (packet_machine) {
183                 if (check_col(pinfo->cinfo, COL_INFO)) 
184                     col_add_fstr(pinfo->cinfo, COL_INFO, "%s %s (%s)",
185                                  proto_name, packet_machine, packet_identity);
186             }
187             else {
188                 if (check_col(pinfo->cinfo, COL_INFO)) 
189                     col_add_fstr(pinfo->cinfo, COL_INFO, "%s ID:%s",
190                                  proto_name, packet_identity);
191             }
192         }
193
194     }
195
196     /* If this protocol has a sub-dissector call it here, see section 1.8 */
197
198     return tvb_length(tvb);
199 }
200
201
202 /* Register the protocol with Wireshark */
203
204 /* this format is require because a script is used to build the C function
205    that calls all the protocol registration.
206 */
207
208 void
209 proto_register_tivoconnect(void)
210 {                 
211     /* Setup list of header fields  See Section 1.6.1 for details*/
212     static hf_register_info hf[] = {
213         { &hf_tivoconnect_flavor,
214             { "Flavor",           "tivoconnect.flavor",
215             FT_STRINGZ, BASE_NONE, NULL, 0,          
216             "Protocol Flavor supported by the originator", HFILL }},
217         { &hf_tivoconnect_method,
218             { "Method",           "tivoconnect.method",
219             FT_STRINGZ, BASE_NONE, NULL, 0,          
220             "Packet was delivered via UDP(broadcast) or TCP(connected)", HFILL }},
221         { &hf_tivoconnect_platform,
222             { "Platform",           "tivoconnect.platform",
223             FT_STRINGZ, BASE_NONE, NULL, 0,          
224             "System platform, either tcd(TiVo) or pc(Computer)", HFILL }},
225         { &hf_tivoconnect_machine,
226             { "Machine",           "tivoconnect.machine",
227             FT_STRINGZ, BASE_NONE, NULL, 0,          
228             "Human-readable system name", HFILL }},
229         { &hf_tivoconnect_identity,
230             { "Identity",           "tivoconnect.identity",
231             FT_STRINGZ, BASE_NONE, NULL, 0,          
232             "Unique serial number for the system", HFILL }},
233         { &hf_tivoconnect_services,
234             { "Services",           "tivoconnect.services",
235             FT_STRINGZ, BASE_NONE, NULL, 0,          
236             "List of available services on the system", HFILL }},
237         { &hf_tivoconnect_version,
238             { "Version",           "tivoconnect.version",
239             FT_STRINGZ, BASE_NONE, NULL, 0,          
240             "System software version", HFILL }},
241     };
242
243     /* Setup protocol subtree array */
244     static gint *ett[] = {
245         &ett_tivoconnect,
246     };
247
248     /* Register the protocol name and description */
249     proto_tivoconnect = proto_register_protocol("TiVoConnect Discovery Protocol",
250         "TiVoConnect", "tivoconnect");
251
252     /* Required function calls to register the header fields and subtrees used */
253     proto_register_field_array(proto_tivoconnect, hf, array_length(hf));
254     proto_register_subtree_array(ett, array_length(ett));
255 }
256
257
258 void
259 proto_reg_handoff_tivoconnect(void)
260 {
261     dissector_handle_t tivoconnect_handle;
262
263     tivoconnect_handle = new_create_dissector_handle(dissect_tivoconnect, proto_tivoconnect);
264     dissector_add("udp.port", 2190, tivoconnect_handle);
265     dissector_add("tcp.port", 2190, tivoconnect_handle);
266 }