Add dissection of one more bit in Quota FS Flags bitmask
[obnox/wireshark/wip.git] / packet-skinny.c
1 /* packet-skinny.c
2  *
3  * Dissector for the Skinny Client Control Protocol
4  *   (The "D-Channel"-Protocol for Cisco Systems' IP-Phones)
5  * Copyright 2001, Joerg Mayer (email: see AUTHORS file)
6  *
7  * Further decode work by pee@erkkila.org 
8  *
9  * This file is based on packet-aim.c, which is
10  * Copyright 2000, Ralf Hoelzer <ralf@well.com>
11  *
12  * $Id: packet-skinny.c,v 1.10 2002/03/18 00:45:10 guy Exp $
13  *
14  * Ethereal - Network traffic analyzer
15  * By Gerald Combs <gerald@ethereal.com>
16  * Copyright 1998 Gerald Combs
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 /* This implementation is based on a draft version of the 3.0
34  * specification
35  */
36
37 #ifdef HAVE_CONFIG_H
38 # include "config.h"
39 #endif
40
41 #include <string.h>
42
43 #include <epan/packet.h>
44
45 #define TCP_PORT_SKINNY 2000
46
47 /* I will probably need this again when I change things
48  * to function pointers, but let me use the existing
49  * infrastructure for now
50  *
51  * typedef struct {
52  *   guint32    id;
53  *   char *     name;
54  * } message_id_t;
55  */
56
57 static const value_string  message_id[] = {
58
59   /* Station -> Callmanager */
60   {0x0000, "KeepAliveMessage"},
61   {0x0001, "RegisterMessage"},
62   {0x0002, "IpPortMessage"},
63   {0x0003, "KeypadButtonMessage"},
64   {0x0004, "EnblocCallMessage"},
65   {0x0005, "StimulusMessage"},
66   {0x0006, "OffHookMessage"},
67   {0x0007, "OnHookMessage"},
68   {0x0008, "HookFlashMessage"},
69   {0x0009, "ForwardStatReqMessage"},
70   {0x000A, "SpeedDialStatReqMessage"},
71   {0x000B, "LineStatReqMessage"},
72   {0x000C, "ConfigStatReqMessage"},
73   {0x000D, "TimeDateReqMessage"},
74   {0x000E, "ButtonTemplateReqMessage"},
75   {0x000F, "VersionReqMessage"},
76   {0x0010, "CapabilitiesResMessage"},
77   {0x0011, "MediaPortListMessage"},
78   {0x0012, "ServerReqMessage"},
79   {0x0020, "AlarmMessage"},
80   {0x0021, "MulticastMediaReceptionAck"},
81   {0x0022, "OpenReceiveChannelAck"},
82   {0x0023, "ConnectionStatisticsRes"},
83   {0x0024, "OffHookWithCgpnMessage"},
84   {0x0025, "SoftKeySetReqMessage"},
85   {0x0026, "SoftKeyEventMessage"},
86   {0x0027, "UnregisterMessage"},
87   {0x0028, "SoftKeyEventMessage"},
88   {0x0029, "RegisterTokenReq"},
89   {0x002B, "unknownClientMessage1"},
90   {0x002D, "unknownClientMessage2"},
91   
92   /* Callmanager -> Station */
93   /* 0x0000, 0x0003? */
94   {0x0081, "RegisterAckMessage"},
95   {0x0082, "StartToneMessage"},
96   {0x0083, "StopToneMessage"},
97   {0x0085, "SetRingerMessage"},
98   {0x0086, "SetLampMessage"},
99   {0x0087, "SetHkFDetectMessage"},
100   {0x0088, "SetSpeakerModeMessage"},
101   {0x0089, "SetMicroModeMessage"},
102   {0x008A, "StartMediaTransmission"},
103   {0x008B, "StopMediaTransmission"},
104   {0x008C, "StartMediaReception"},
105   {0x008D, "StopMediaReception"},
106   {0x008F, "CallInfoMessage"},
107   {0x0090, "ForwardStatMessage"},
108   {0x0091, "SpeedDialStatMessage"},
109   {0x0092, "LineStatMessage"},
110   {0x0093, "ConfigStatMessage"},
111   {0x0094, "DefineTimeDate"},
112   {0x0095, "StartSessionTransmission"},
113   {0x0096, "StopSessionTransmission"},
114   {0x0097, "ButtonTemplateMessage"},
115   {0x0098, "VersionMessage"},
116   {0x0099, "DisplayTextMessage"},
117   {0x009A, "ClearDisplay"},
118   {0x009B, "CapabilitiesReqMessage"},
119   {0x009C, "EnunciatorCommandMessage"},
120   {0x009D, "RegisterRejectMessage"},
121   {0x009E, "ServerResMessage"},
122   {0x009F, "Reset"},
123   {0x0100, "KeepAliveAckMessage"},
124   {0x0101, "StartMulticastMediaReception"},
125   {0x0102, "StartMulticastMediaTransmission"},
126   {0x0103, "StopMulticastMediaReception"},
127   {0x0104, "StopMulticastMediaTransmission"},
128   {0x0105, "OpenReceiveChannel"},
129   {0x0106, "CloseReceiveChannel"},
130   {0x0107, "ConnectionStatisticsReq"},
131   {0x0108, "SoftKeyTemplateResMessage"},
132   {0x0109, "SoftKeySetResMessage"},
133   {0x0110, "SelectSoftKeysMessage"},
134   {0x0111, "CallStateMessage"},
135   {0x0112, "DisplayPromptStatusMessage"},
136   {0x0113, "ClearPromptStatusMessage"},
137   {0x0114, "DisplayNotifyMessage"},
138   {0x0115, "ClearNotifyMessage"},
139   {0x0116, "ActivateCallPlaneMessage"},
140   {0x0117, "DeactivateCallPlaneMessage"},
141   {0x0118, "UnregisterAckMessage"},
142   {0x0119, "BackSpaceReqMessage"},
143   {0x011A, "RegisterTokenAck"},
144   {0x011B, "RegisterTokenReject"},
145   {0x011D, "unknownForwardMessage1"},
146
147   {0     , NULL}        /* needed for value_string automagic */
148 };
149
150 static void dissect_skinny(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
151
152 /* Initialize the protocol and registered fields */
153 static int proto_skinny          = -1;
154 static int hf_skinny_data_length = -1;
155 static int hf_skinny_reserved    = -1;
156 static int hf_skinny_messageid   = -1;
157 static int hf_skinny_callIdentifier = -1;
158 static int hf_skinny_packetsSent = -1;
159 static int hf_skinny_octetsSent  = -1;
160 static int hf_skinny_packetsRecv = -1;
161 static int hf_skinny_octetsRecv  = -1;
162 static int hf_skinny_packetsLost = -1;
163 static int hf_skinny_latency     = -1;
164 static int hf_skinny_jitter      = -1;
165 static int hf_skinny_extension   = -1;
166 static int hf_skinny_displayMessage = -1;
167 static int hf_skinny_timeStamp = -1;
168 static int hf_skinny_unknown = -1;
169 static int hf_skinny_ipDest = -1;
170 static int hf_skinny_ipSrc = -1;
171 static int hf_skinny_dateYear = -1;
172 static int hf_skinny_dateMonth = -1;
173 static int hf_skinny_dateDay = -1;
174 static int hf_skinny_dateHour = -1;
175 static int hf_skinny_dateMinute = -1;
176 static int hf_skinny_destPort = -1;
177 static int hf_skinny_srcPort = -1;
178 static int hf_skinny_softKeyNumber = -1;
179 static int hf_skinny_line = -1;
180 static int hf_skinny_dialedDigit = -1;
181
182 /* Initialize the subtree pointers */
183 static gint ett_skinny          = -1;
184
185 static dissector_handle_t data_handle;
186
187 /* Code to actually dissect the packets */
188 static void dissect_skinny(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
189 {
190   /* The general structure of a packet: {IP-Header|TCP-Header|n*SKINNY}
191    * SKINNY-Packet: {Header(Size, Reserved)|Data(MessageID, Message-Data)}
192    */
193   
194
195
196   /* Header fields */
197   guint32 hdr_data_length;
198   guint32 hdr_reserved;
199   guint32 data_messageid;
200   gchar   *messageid_str;
201   /*  guint32 data_size; */
202
203   guint32 offset = 0;
204
205   guint32 callIdentifier = 0;
206   guint32 packetsSent = 0;
207   guint32 octetsSent = 0;
208   guint32 packetsRecv = 0;
209   guint32 octetsRecv = 0;
210   guint32 packetsLost = 0; 
211   guint32 latency = 0;
212   guint32 jitter = 0;
213   guint32 timeStamp = 0;
214   guint32 ipSrc = 0;
215   guint32 ipDest = 0;
216   guint32 year = 0;
217   guint32 month = 0;
218   guint32 day = 0;
219   guint32 hour = 0;
220   guint32 minute = 0;
221   guint32 destPort = 0;
222   guint32 srcPort = 0;
223   guint32 softKeyNumber = 0;
224   guint32 line = 0;
225   guint32 dialedDigit = 0;
226
227   guint32 unknown1 = 0;
228   guint32 unknown2 = 0;
229   guint32 unknown3 = 0;
230   guint32 unknown4 = 0;
231   guint32 unknown5 = 0;
232   guint32 unknown6 = 0;
233   guint32 unknown7 = 0;
234   guint32 unknown8 = 0;
235   guint32 unknown9 = 0;
236   guint32 unknown10 = 0;
237   guint32 unknown11 = 0;
238
239   int extensionLength = 10;
240   int displayLength   = 100;
241   char extension[extensionLength];
242   char displayMessage[displayLength];
243   int softKeyLoop = 0;
244   
245   /* Set up structures we will need to add the protocol subtree and manage it */
246   proto_item *ti;
247   proto_tree *skinny_tree = NULL;
248   
249   /* check, if this is really an SKINNY packet, they start with a length + 0 */
250   
251   /* get relevant header information */
252   hdr_data_length = tvb_get_letohl(tvb, 0);
253   hdr_reserved    = tvb_get_letohl(tvb, 4);
254   data_messageid   = tvb_get_letohl(tvb, 8);
255
256
257   /*  data_size       = MIN(8+hdr_data_length, tvb_length(tvb)) - 0xC; */
258   
259   /* hdr_data_length > 1024 is just a heuristic. Better values/checks welcome */
260   if (hdr_data_length < 4 || hdr_data_length > 1024 || hdr_reserved != 0) {
261     /* Not an SKINNY packet, just happened to use the same port */
262     call_dissector(data_handle,tvb, pinfo, tree);
263     return;
264   }
265   
266   /* Make entries in Protocol column and Info column on summary display */
267   if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
268     col_set_str(pinfo->cinfo, COL_PROTOCOL, "SKINNY");
269   }
270   
271   if (check_col(pinfo->cinfo, COL_INFO)) {
272     col_set_str(pinfo->cinfo, COL_INFO, "Skinny Client Control Protocol");
273   }
274   
275   while (tvb_reported_length_remaining(tvb, offset) != 0) {
276
277     hdr_data_length = tvb_get_letohl(tvb, offset);
278     hdr_reserved    = tvb_get_letohl(tvb, offset+4);
279     data_messageid  = tvb_get_letohl(tvb, offset+8);
280
281     /* In the interest of speed, if "tree" is NULL, don't do any work not
282      * necessary to generate protocol tree items. */
283     if (tree) {
284       ti = proto_tree_add_item(tree, proto_skinny, tvb, offset, hdr_data_length+8, FALSE); 
285       skinny_tree = proto_item_add_subtree(ti, ett_skinny);
286       proto_tree_add_uint(skinny_tree, hf_skinny_data_length, tvb, offset, 4, hdr_data_length);  
287       proto_tree_add_uint(skinny_tree, hf_skinny_reserved, tvb, offset+4, 4, hdr_reserved);
288     }
289
290     messageid_str = val_to_str(data_messageid, message_id, "0x%08X (Unknown)");
291
292     if (check_col(pinfo->cinfo, COL_INFO)) {
293       col_add_str(pinfo->cinfo, COL_INFO, messageid_str);
294     }
295
296     if (tree) {
297       proto_tree_add_uint(skinny_tree, hf_skinny_messageid, tvb,offset+8, 4, data_messageid );
298     }
299
300     if (tree) {
301       switch(data_messageid) {
302
303         /* cases that do not need to be decoded */
304       case 0x0 :    /* keepAlive */
305         break;
306
307       case 0x6 :    /* offHook */
308         break;
309
310       case 0x7 :    /* onHook    */
311         break;
312
313       case 0xd :    /* timeDateReqMessage */
314         break;
315
316       case 0xe :    /* buttoneTemplateReqMessage */
317         break;
318
319       case 0x25 :   /* softKeySetReqMessage */
320         break;
321
322       case 0x27 :   /* unregisterMessage */
323         break;
324
325       case 0x28 :   /* softKeyEventMessage */
326         break;
327
328       case 0x83 :   /* stopTone */
329         break;
330
331       case 0x9b :   /* capabilitiesReqMessage */
332         break;
333
334       case 0x100 :    /* keepAliveAck */
335         break;
336         
337         /*
338         ** cases that need decode
339         **
340         */
341
342       case 0x1 :   /* register message */
343         memset(displayMessage, '\0', displayLength);
344         tvb_memcpy(tvb, displayMessage, offset+12, 15); /* Note hack on field size ^_^ */
345         unknown1 = tvb_get_letohl(tvb, offset+28);
346         unknown2 = tvb_get_letohl(tvb, offset+32);
347         tvb_memcpy(tvb, (guint8 *)&ipSrc, offset+36,4);
348         unknown4 = tvb_get_letohl(tvb, offset+40);
349         unknown5 = tvb_get_letohl(tvb, offset+44);
350         unknown6 = tvb_get_letohl(tvb, offset+48);
351         unknown7 = tvb_get_letohl(tvb, offset+52);
352
353         proto_tree_add_string(skinny_tree, hf_skinny_displayMessage, tvb, offset+12, strlen(displayMessage), displayMessage);
354         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+28, 4, unknown1);
355         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+32, 4, unknown2);
356         proto_tree_add_ipv4(skinny_tree, hf_skinny_ipSrc, tvb, offset+36, 4, ipSrc);
357         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+40, 4, unknown4);
358         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+44, 4, unknown5);
359         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+48, 4, unknown6);
360         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+52, 4, unknown7);
361         break;
362
363       case 0x2 :  /* ipPortMessage */
364         srcPort = tvb_get_ntohs(tvb, offset+12);
365         
366         proto_tree_add_uint(skinny_tree, hf_skinny_srcPort, tvb, offset+12, 4, srcPort);
367         break;
368
369       case 0x3 :  /* keyPadButtonMessage */
370         dialedDigit = tvb_get_letohl(tvb, offset+12);
371         
372         proto_tree_add_uint(skinny_tree, hf_skinny_dialedDigit, tvb, offset+12, 4, dialedDigit);
373         break;
374
375       case 0x5 :
376         unknown1 = tvb_get_letohl(tvb, offset+12);
377         unknown2 = tvb_get_letohl(tvb, offset+16);
378
379         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
380         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+16, 4, unknown2);
381         break;
382
383       case 0xa :  /* speedDialStatReqMessage */
384         line = tvb_get_letohl(tvb, offset+12);
385
386         proto_tree_add_uint(skinny_tree, hf_skinny_line, tvb, offset+12, 4, line);
387         break;
388
389       case 0xb :  /* LineStatReqMessage */
390         line = tvb_get_letohl(tvb, offset+12);
391
392         proto_tree_add_uint(skinny_tree, hf_skinny_line, tvb, offset+12, 4, line);
393         break;
394
395       case 0x10 :  /* capabilitiesResMessage ===== LOTS to decode here, check jtapi */
396         break;
397
398       case 0x20 :   /* alarmMessage */
399         unknown1   = tvb_get_letohl(tvb,offset+12);
400         memset(displayMessage, '\0', displayLength);
401         tvb_memcpy(tvb, displayMessage, offset+16, 76); /* Note hack on field size ^_^ */
402         unknown2 = tvb_get_letohl(tvb, offset+92);
403         unknown3 = tvb_get_letohl(tvb, offset+96);
404         unknown4 = tvb_get_letohl(tvb, offset+100);
405         tvb_memcpy(tvb, (guint8 *)&ipSrc, offset+100,4);
406
407         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
408         proto_tree_add_string(skinny_tree, hf_skinny_displayMessage, tvb, offset+16, strlen(displayMessage), displayMessage);
409         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+92, 4, unknown2);
410         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+96, 4, unknown3);
411         proto_tree_add_ipv4(skinny_tree, hf_skinny_ipSrc,   tvb, offset+100, 4, ipSrc);
412         break;
413
414       case 0x22 :
415         unknown1 = tvb_get_letohl(tvb, offset+12);
416         tvb_memcpy(tvb, (guint8 *)&ipSrc, offset+16,4);
417         srcPort  = tvb_get_letohl(tvb, offset+20);
418         unknown3 = tvb_get_letohl(tvb, offset+24);
419
420         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
421         proto_tree_add_ipv4(skinny_tree, hf_skinny_ipSrc,   tvb, offset+16, 4, ipSrc);
422         proto_tree_add_uint(skinny_tree, hf_skinny_srcPort, tvb, offset+20, 4, srcPort);
423         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+24, 4, unknown3);
424         break;  
425
426       case 0x26 :  /* softKeyEventMessage */
427         unknown1 = tvb_get_letohl(tvb, offset+12);
428         unknown2 = tvb_get_letohl(tvb, offset+16);
429         callIdentifier = tvb_get_letohl(tvb, offset+20);
430
431         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
432         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+16, 4, unknown2);
433         proto_tree_add_uint(skinny_tree, hf_skinny_callIdentifier, tvb, offset+20, 4, callIdentifier);
434         break;
435
436       case 0x2b :  /* unknownClientMessage1 */
437         unknown1 = tvb_get_letohl(tvb, offset+12);
438
439         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
440         break;
441
442       case 0x2d :  /* unknownClientMessage2 */
443         unknown1 = tvb_get_letohl(tvb, offset+12);
444
445         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
446         break;
447
448       case 0x81 :  /* registerAck */
449         unknown1 = tvb_get_letohl(tvb, offset+12);
450         unknown2 = tvb_get_letohl(tvb, offset+16);
451         unknown3 = tvb_get_letohl(tvb, offset+20);
452         unknown4 = tvb_get_letohl(tvb, offset+24);
453
454         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
455         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+16, 4, unknown2);
456         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+20, 4, unknown3);
457         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+24, 4, unknown4);
458         break;
459
460       case 0x82 :  /* startTone */
461         unknown1 = tvb_get_letohl(tvb, offset+12);
462         
463         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
464         break;
465
466       case 0x85 :
467         unknown1 = tvb_get_letohl(tvb, offset+12);
468
469         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
470         break;
471         
472       case 0x86 :
473         unknown1 = tvb_get_letohl(tvb, offset+12);
474         unknown2 = tvb_get_letohl(tvb, offset+16);
475         unknown3 = tvb_get_letohl(tvb, offset+20);
476
477         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
478         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+16, 4, unknown2);
479         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+20, 4, unknown3);
480         break;
481
482       case 0x88 :
483         unknown1 = tvb_get_letohl(tvb, offset+12);
484
485         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
486         break;
487         
488       case 0x8a :
489         unknown1  = tvb_get_letohl(tvb, offset+12);
490         unknown2  = tvb_get_letohl(tvb, offset+16);
491         tvb_memcpy(tvb, (guint8 *)&ipDest, offset+20,4);
492         destPort  = tvb_get_letohl(tvb, offset+24);
493         unknown5  = tvb_get_letohl(tvb, offset+28);
494         unknown6  = tvb_get_letohl(tvb, offset+32);
495         unknown7  = tvb_get_letohl(tvb, offset+36);
496         unknown8  = tvb_get_letohl(tvb, offset+40);
497         unknown9  = tvb_get_letohl(tvb, offset+44);
498         unknown10 = tvb_get_letohl(tvb, offset+48);
499
500         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
501         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+16, 4, unknown2);
502         proto_tree_add_ipv4(skinny_tree, hf_skinny_ipDest,   tvb, offset+20, 4, ipDest);
503         proto_tree_add_uint(skinny_tree, hf_skinny_destPort,tvb, offset+24, 4, destPort);
504         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+28, 4, unknown5);
505         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+32, 4, unknown6);
506         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+36, 4, unknown7);
507         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+40, 4, unknown8);
508         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+44, 4, unknown9);
509         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+48, 4, unknown10);
510         break;
511
512       case 0x8b :  /* stopMediaTransmission */
513         unknown1 = tvb_get_letohl(tvb, offset+12);
514         unknown2 = tvb_get_letohl(tvb, offset+16);
515
516         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
517         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+16, 4, unknown2);
518         break;
519
520       case 0x91 : /* speedDialStatMessage */
521         line = tvb_get_letohl(tvb, offset+12);
522         
523         proto_tree_add_uint(skinny_tree, hf_skinny_line, tvb, offset+12, 4, line);
524         break;
525
526       case 0x92 : /* lineStatMessage */
527         line = tvb_get_letohl(tvb, offset+12);
528
529         proto_tree_add_uint(skinny_tree, hf_skinny_line, tvb, offset+12, 4, line);
530         break;
531
532       case 0x94 :
533         year      = tvb_get_letohl(tvb, offset+12);
534         month     = tvb_get_letohl(tvb, offset+16);
535         unknown1  = tvb_get_letohl(tvb, offset+20);
536         day       = tvb_get_letohl(tvb, offset+24);
537         hour      = tvb_get_letohl(tvb, offset+28);
538         minute    = tvb_get_letohl(tvb, offset+32);
539         unknown2  = tvb_get_letohl(tvb, offset+36);
540         unknown3  = tvb_get_letohl(tvb, offset+40);
541         timeStamp = tvb_get_letohl(tvb, offset+44);
542
543         proto_tree_add_uint(skinny_tree, hf_skinny_dateYear,  tvb, offset+12, 4, year);
544         proto_tree_add_uint(skinny_tree, hf_skinny_dateMonth, tvb, offset+16, 4, month);
545         proto_tree_add_uint(skinny_tree, hf_skinny_unknown,   tvb, offset+20, 4, unknown1);
546         proto_tree_add_uint(skinny_tree, hf_skinny_dateDay,   tvb, offset+24, 4, day);
547         proto_tree_add_uint(skinny_tree, hf_skinny_dateHour,  tvb, offset+28, 4, hour);
548         proto_tree_add_uint(skinny_tree, hf_skinny_dateMinute,tvb, offset+32, 4, minute);
549         proto_tree_add_uint(skinny_tree, hf_skinny_unknown,   tvb, offset+36, 4, unknown2);
550         proto_tree_add_uint(skinny_tree, hf_skinny_unknown,   tvb, offset+40, 4, unknown3);
551         proto_tree_add_uint(skinny_tree, hf_skinny_timeStamp, tvb, offset+44, 4, timeStamp);
552         break;
553         
554       case 0x97 :  /* buttonTemplateMessage === LOTS here check jtapi for hints */
555         break;
556
557       case 0x99 :  /* displayTextMessage */
558         memset(displayMessage, '\0', displayLength);
559         tvb_memcpy(tvb, displayMessage, offset+12, 32);
560         unknown1  = tvb_get_letohl(tvb, offset+44);
561
562         proto_tree_add_string(skinny_tree, hf_skinny_displayMessage, tvb, offset+12, strlen(displayMessage), displayMessage);     
563         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+44, 4, unknown1);
564         break;
565
566       case 0x9f :   /* reset */
567         unknown1  = tvb_get_letohl(tvb, offset+12);
568         
569         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
570         break;
571
572       case 0x106 :  /* closeReceiveChannel */
573         unknown1 = tvb_get_letohl(tvb, offset+12);
574         unknown2 = tvb_get_letohl(tvb, offset+16);
575
576         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
577         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+16, 4, unknown2);
578         break;
579
580       case 0x105 :
581         unknown1 = tvb_get_letohl(tvb, offset+12);
582         unknown2 = tvb_get_letohl(tvb, offset+16);
583         unknown3 = tvb_get_letohl(tvb, offset+20);
584         unknown4 = tvb_get_letohl(tvb, offset+24);
585         unknown5 = tvb_get_letohl(tvb, offset+28);
586         unknown6 = tvb_get_letohl(tvb, offset+32);
587
588         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
589         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+16, 4, unknown2);
590         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+20, 4, unknown3);
591         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+24, 4, unknown4);
592         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+28, 4, unknown5);
593         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+32, 4, unknown6);
594         break;
595
596       case 0x107 :      
597         memset(extension, '\0', extensionLength);
598         tvb_get_nstringz0(tvb, offset+12, extensionLength, extension);
599         callIdentifier = tvb_get_letohl(tvb, offset+36);
600
601         proto_tree_add_string(skinny_tree, hf_skinny_extension, tvb, offset+12, strlen(extension), extension);
602         proto_tree_add_uint(skinny_tree, hf_skinny_callIdentifier, tvb, offset+36, 4, callIdentifier);
603         break;
604
605       case 0x108 :   /* softkeyTemplateResMessage == Jtapi again :P, can decode some*/
606         unknown1  = tvb_get_letohl(tvb, offset+12);
607         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
608
609         unknown2  = tvb_get_letohl(tvb, offset+16);
610         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+16, 4, unknown2);
611
612         unknown3  = tvb_get_letohl(tvb, offset+20);
613         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+20, 4, unknown3);
614
615         softKeyNumber = 0;
616         softKeyLoop = 0;
617         /* NOTE ***** This loop *MIGHT* need to revolve around the unknow1/2 properties, not sure though */
618         while (softKeyLoop < 18) {
619           int softOffset = offset+(softKeyLoop*20);
620           memset(displayMessage, '\0', displayLength);
621           tvb_memcpy(tvb, displayMessage, softOffset+24, 16);
622           proto_tree_add_string(skinny_tree, hf_skinny_displayMessage, tvb, softOffset+24, strlen(displayMessage), displayMessage);
623           softKeyNumber = tvb_get_letohl(tvb, softOffset+40);
624           proto_tree_add_uint(skinny_tree, hf_skinny_softKeyNumber, tvb, softOffset+40, 4, softKeyNumber);
625
626           softKeyLoop++;
627         }
628
629         break;
630
631       case 0x110 :
632         unknown1       = tvb_get_letohl(tvb, offset+12);
633         callIdentifier = tvb_get_letohl(tvb, offset+16);
634         unknown2       = tvb_get_letohl(tvb, offset+20);
635         unknown3       = tvb_get_letohl(tvb, offset+24);
636
637         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
638         proto_tree_add_uint(skinny_tree, hf_skinny_callIdentifier, tvb, offset+16, 4, callIdentifier);
639         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+20, 4, unknown2);
640         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+24, 4, unknown3);
641         break;
642         
643       case 0x111 :
644         unknown1 = tvb_get_letohl(tvb, offset+12);
645         unknown2 = tvb_get_letohl(tvb, offset+16);
646         callIdentifier = tvb_get_letohl(tvb, offset+20);
647
648         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
649         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+16, 4, unknown2);
650         proto_tree_add_uint(skinny_tree, hf_skinny_callIdentifier, tvb, offset+20, 4, callIdentifier);
651         break;
652         
653       case 0x112 :
654         memset(displayMessage,'\0',displayLength);
655         unknown1 = tvb_get_letohl(tvb, offset+12);
656         tvb_get_nstringz0(tvb,offset+16,displayLength, displayMessage);
657         unknown2 = tvb_get_letohl(tvb, offset+48);
658         callIdentifier = tvb_get_letohl(tvb, offset+52);
659
660         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
661         proto_tree_add_string(skinny_tree, hf_skinny_displayMessage, tvb, offset+16, strlen(displayMessage), displayMessage);
662         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+48, 4, unknown2);
663         proto_tree_add_uint(skinny_tree, hf_skinny_callIdentifier, tvb, offset+52, 4, callIdentifier);
664         break;
665         
666       case 0x113:
667         callIdentifier = tvb_get_letohl(tvb, offset+16);
668         proto_tree_add_uint(skinny_tree, hf_skinny_callIdentifier, tvb, offset+16, 4, callIdentifier);
669         break;
670         
671       case 0x114 :
672         
673         unknown1 = tvb_get_letohl(tvb, offset+12);
674         memset(displayMessage,'\0',displayLength);
675         tvb_memcpy(tvb, displayMessage, offset+16, 16);
676         unknown2 = tvb_get_letohl(tvb, offset+32);
677         unknown3 = tvb_get_letohl(tvb, offset+36);
678         unknown4 = tvb_get_letohl(tvb, offset+40);
679         unknown5 = tvb_get_letohl(tvb, offset+44);
680
681         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
682         proto_tree_add_string(skinny_tree, hf_skinny_displayMessage, tvb, offset+16, strlen(displayMessage), displayMessage);
683         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+32, 4, unknown2);
684         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+36, 4, unknown3);
685         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+40, 4, unknown4);
686         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+44, 4, unknown5);
687         break;
688         
689       case 0x116 :
690         unknown1 = tvb_get_letohl(tvb, offset+12);
691
692         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
693         break;
694
695       case 0x118 :    /* unregisterAckMessage */
696         unknown1 = tvb_get_letohl(tvb, offset+12);
697
698         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
699         break;
700
701       case 0x0023    :
702         
703         memset(extension,'\0', extensionLength);
704         tvb_get_nstringz0(tvb,offset+12,extensionLength,extension);
705         callIdentifier = tvb_get_letohl(tvb,offset+36);
706         packetsSent    = tvb_get_letohl(tvb,offset+44);
707         octetsSent     = tvb_get_letohl(tvb,offset+48);
708         packetsRecv    = tvb_get_letohl(tvb,offset+52);
709         octetsRecv     = tvb_get_letohl(tvb,offset+56);
710         packetsLost    = tvb_get_letohl(tvb,offset+60);
711         jitter         = tvb_get_letohl(tvb,offset+64);
712         latency        = tvb_get_letohl(tvb,offset+68);
713
714         proto_tree_add_string(skinny_tree, hf_skinny_extension, tvb, offset+12, strlen(extension), extension);
715         proto_tree_add_uint(skinny_tree, hf_skinny_callIdentifier, tvb, offset+36, 4, callIdentifier);
716         proto_tree_add_uint(skinny_tree, hf_skinny_packetsSent, tvb, offset+44, 4, packetsSent);
717         proto_tree_add_uint(skinny_tree, hf_skinny_octetsSent, tvb, offset+48, 4, octetsSent);
718         proto_tree_add_uint(skinny_tree, hf_skinny_packetsRecv, tvb, offset+52, 4, packetsRecv);
719         proto_tree_add_uint(skinny_tree, hf_skinny_octetsRecv, tvb, offset+56, 4, octetsRecv);
720         proto_tree_add_uint(skinny_tree, hf_skinny_packetsLost, tvb, offset+60, 4, packetsLost);
721         proto_tree_add_uint(skinny_tree, hf_skinny_latency, tvb, offset+64, 4, latency);
722         proto_tree_add_uint(skinny_tree, hf_skinny_jitter, tvb, offset+68, 4, jitter);
723         break;
724         
725       case 0x11D :
726         unknown1       = tvb_get_letohl(tvb, offset+36);
727         callIdentifier = tvb_get_letohl(tvb, offset+40);
728
729         proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+36, 4, unknown1);
730         proto_tree_add_uint(skinny_tree, hf_skinny_callIdentifier, tvb, offset+40, 4, callIdentifier);
731         break;
732
733         
734       default:
735         break;
736       }
737       
738     }
739     offset = offset + hdr_data_length+8;
740   }
741 }
742
743 /* Register the protocol with Ethereal */
744 void 
745 proto_register_skinny(void)
746 {                 
747   
748   /* Setup list of header fields */
749   static hf_register_info hf[] = {
750     { &hf_skinny_data_length,
751       { "Data Length", "skinny.data_length",
752         FT_UINT32, BASE_DEC, NULL, 0x0,
753         "Number of bytes in the data portion.",
754         HFILL }
755     },
756     { &hf_skinny_reserved,
757       { "Reserved", "skinny.reserved",
758         FT_UINT32, BASE_HEX, NULL, 0x0,
759         "Reserved for furture(?) use.",
760         HFILL }
761     },
762     /* FIXME: Enable use of message name ???  */
763     { &hf_skinny_messageid,
764       { "Message ID", "skinny.messageid",
765         FT_UINT32, BASE_HEX, VALS(message_id), 0x0,
766         "The function requested/done with this message.",
767         HFILL }
768     },
769
770     { &hf_skinny_callIdentifier,
771       { "Call Identifier", "skinny.callIdentifier",
772         FT_UINT32, BASE_DEC, NULL, 0x0,
773         "Call identifier for this call.",
774         HFILL }
775     },
776
777     { &hf_skinny_packetsSent,
778       { "Packets Sent", "skinny.packetsSent",
779         FT_UINT32, BASE_DEC, NULL, 0x0,
780         "Packets Sent during the call.",
781         HFILL }
782     },
783
784     { &hf_skinny_octetsSent,
785       { "Octets Sent", "skinny.octetsSent",
786         FT_UINT32, BASE_DEC, NULL, 0x0,
787         "Octets sent during the call.",
788         HFILL }
789     },
790
791     { &hf_skinny_packetsRecv,
792       { "Packets Received", "skinny.packetsRecv",
793         FT_UINT32, BASE_DEC, NULL, 0x0,
794         "Packets received during the call.",
795         HFILL }
796     },
797
798
799     { &hf_skinny_octetsRecv,
800       { "Octets Received", "skinny.octetsRecv",
801         FT_UINT32, BASE_DEC, NULL, 0x0,
802         "Octets received during the call.",
803         HFILL }
804     },
805
806
807     { &hf_skinny_packetsLost,
808       { "Packets Lost", "skinny.packetsLost",
809         FT_UINT32, BASE_DEC, NULL, 0x0,
810         "Packets lost during the call.",
811         HFILL }
812     },
813
814
815     { &hf_skinny_latency,
816       { "Latency(ms)", "skinny.latency",
817         FT_UINT32, BASE_DEC, NULL, 0x0,
818         "Average packet latency during the call.",
819         HFILL }
820     },
821
822     { &hf_skinny_jitter,
823       { "Jitter", "skinny.jitter",
824         FT_UINT32, BASE_DEC, NULL, 0x0,
825         "Average jitter during the call.",
826         HFILL }
827     },
828
829     { &hf_skinny_extension,
830       { "Extension", "skinny.extension",
831         FT_STRING, BASE_NONE, NULL, 0x0,
832         "The extension this packets is for.",
833         HFILL }
834     },
835
836     { &hf_skinny_displayMessage,
837       { "Text", "skinny.displayMessage",
838         FT_STRING, BASE_NONE, NULL, 0x0,
839         "The message displayed on the phone.",
840         HFILL }
841     },
842
843     { &hf_skinny_timeStamp,
844       { "Timestamp", "skinny.timeStamp",
845         FT_UINT32, BASE_DEC, NULL, 0x0,
846         "Time stamp for the call reference",
847         HFILL }
848     },
849
850     { &hf_skinny_unknown,
851       { "Unknown Long", "skinny.unknown",
852         FT_UINT32, BASE_HEX, NULL, 0x0,
853         "An as yet undecoded long value",
854         HFILL }
855     },
856    
857     { &hf_skinny_ipSrc,
858       { "IP Source", "skinny.ipSrc",
859         FT_IPv4, BASE_NONE, NULL, 0x0,
860         "Ip source address",
861         HFILL }
862     },
863
864     { &hf_skinny_ipDest,
865       { "IP Destination", "skinny.ipDest",
866         FT_IPv4, BASE_NONE, NULL, 0x0,
867         "IP destination address",
868         HFILL }
869     },
870
871     { &hf_skinny_dateYear,
872       { "Year", "skinny.year",
873         FT_UINT32, BASE_DEC, NULL, 0x0,
874         "The current year",
875         HFILL }
876     },
877
878     { &hf_skinny_dateMonth,
879       { "Month", "skinny.month",
880         FT_UINT32, BASE_DEC, NULL, 0x0,
881         "The current month",
882         HFILL }
883     },
884
885     { &hf_skinny_dateDay,
886       { "Day", "skinny.day",
887         FT_UINT32, BASE_DEC, NULL, 0x0,
888         "The day of the current month",
889         HFILL }
890     },
891
892     { &hf_skinny_dateHour,
893       { "Hour", "skinny.hour",
894         FT_UINT32, BASE_DEC, NULL, 0x0,
895         "Hour of the day",
896         HFILL }
897     },
898
899     { &hf_skinny_dateMinute,
900       { "Minute", "skinny.minute",
901         FT_UINT32, BASE_DEC, NULL, 0x0,
902         "Minute",
903         HFILL }
904     },
905
906     { &hf_skinny_destPort,
907       { "Destination Port", "skinny.destPort",
908         FT_UINT32, BASE_DEC, NULL, 0x0,
909         "Destination Port",
910         HFILL }
911     },
912
913     { &hf_skinny_srcPort,
914       { "Source Port", "skinny.srcPort",
915         FT_UINT32, BASE_DEC, NULL, 0x0,
916         "Source Port",
917         HFILL }
918     },
919
920     { &hf_skinny_softKeyNumber,
921       { "SoftKey", "skinny.softKeyNumber",
922         FT_UINT32, BASE_DEC, NULL, 0x0,
923         "SoftKey",
924         HFILL }
925     },
926
927     { &hf_skinny_dialedDigit,
928       { "Dialed Digit", "skinny.dialedDigit",
929         FT_UINT32, BASE_DEC, NULL, 0x0,
930         "Dialed Digit",
931         HFILL }
932     },
933
934     { &hf_skinny_line,
935       { "Line", "skinny.line",
936         FT_UINT32, BASE_DEC, NULL, 0x0,
937         "Line",
938         HFILL }
939     },
940
941   };
942   
943   /* Setup protocol subtree array */
944   static gint *ett[] = {
945     &ett_skinny,
946   };
947   
948   /* Register the protocol name and description */
949   proto_skinny = proto_register_protocol("Skinny Client Control Protocol",
950                                          "SKINNY", "skinny");
951   
952   /* Required function calls to register the header fields and subtrees used */
953   proto_register_field_array(proto_skinny, hf, array_length(hf));
954   proto_register_subtree_array(ett, array_length(ett));
955 };
956
957 void
958 proto_reg_handoff_skinny(void)
959 {
960   dissector_handle_t skinny_handle;
961
962   data_handle = find_dissector("data");
963   skinny_handle = create_dissector_handle(dissect_skinny, proto_skinny);
964   dissector_add("tcp.port", TCP_PORT_SKINNY, skinny_handle);
965 }