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)
7 * Further decode work by pee@erkkila.org
9 * This file is based on packet-aim.c, which is
10 * Copyright 2000, Ralf Hoelzer <ralf@well.com>
12 * $Id: packet-skinny.c,v 1.10 2002/03/18 00:45:10 guy Exp $
14 * Ethereal - Network traffic analyzer
15 * By Gerald Combs <gerald@ethereal.com>
16 * Copyright 1998 Gerald Combs
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.
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.
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.
33 /* This implementation is based on a draft version of the 3.0
43 #include <epan/packet.h>
45 #define TCP_PORT_SKINNY 2000
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
57 static const value_string message_id[] = {
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"},
92 /* Callmanager -> Station */
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"},
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"},
147 {0 , NULL} /* needed for value_string automagic */
150 static void dissect_skinny(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
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;
182 /* Initialize the subtree pointers */
183 static gint ett_skinny = -1;
185 static dissector_handle_t data_handle;
187 /* Code to actually dissect the packets */
188 static void dissect_skinny(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
190 /* The general structure of a packet: {IP-Header|TCP-Header|n*SKINNY}
191 * SKINNY-Packet: {Header(Size, Reserved)|Data(MessageID, Message-Data)}
197 guint32 hdr_data_length;
198 guint32 hdr_reserved;
199 guint32 data_messageid;
200 gchar *messageid_str;
201 /* guint32 data_size; */
205 guint32 callIdentifier = 0;
206 guint32 packetsSent = 0;
207 guint32 octetsSent = 0;
208 guint32 packetsRecv = 0;
209 guint32 octetsRecv = 0;
210 guint32 packetsLost = 0;
213 guint32 timeStamp = 0;
221 guint32 destPort = 0;
223 guint32 softKeyNumber = 0;
225 guint32 dialedDigit = 0;
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;
239 int extensionLength = 10;
240 int displayLength = 100;
241 char extension[extensionLength];
242 char displayMessage[displayLength];
245 /* Set up structures we will need to add the protocol subtree and manage it */
247 proto_tree *skinny_tree = NULL;
249 /* check, if this is really an SKINNY packet, they start with a length + 0 */
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);
257 /* data_size = MIN(8+hdr_data_length, tvb_length(tvb)) - 0xC; */
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);
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");
271 if (check_col(pinfo->cinfo, COL_INFO)) {
272 col_set_str(pinfo->cinfo, COL_INFO, "Skinny Client Control Protocol");
275 while (tvb_reported_length_remaining(tvb, offset) != 0) {
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);
281 /* In the interest of speed, if "tree" is NULL, don't do any work not
282 * necessary to generate protocol tree items. */
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);
290 messageid_str = val_to_str(data_messageid, message_id, "0x%08X (Unknown)");
292 if (check_col(pinfo->cinfo, COL_INFO)) {
293 col_add_str(pinfo->cinfo, COL_INFO, messageid_str);
297 proto_tree_add_uint(skinny_tree, hf_skinny_messageid, tvb,offset+8, 4, data_messageid );
301 switch(data_messageid) {
303 /* cases that do not need to be decoded */
304 case 0x0 : /* keepAlive */
307 case 0x6 : /* offHook */
310 case 0x7 : /* onHook */
313 case 0xd : /* timeDateReqMessage */
316 case 0xe : /* buttoneTemplateReqMessage */
319 case 0x25 : /* softKeySetReqMessage */
322 case 0x27 : /* unregisterMessage */
325 case 0x28 : /* softKeyEventMessage */
328 case 0x83 : /* stopTone */
331 case 0x9b : /* capabilitiesReqMessage */
334 case 0x100 : /* keepAliveAck */
338 ** cases that need decode
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);
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);
363 case 0x2 : /* ipPortMessage */
364 srcPort = tvb_get_ntohs(tvb, offset+12);
366 proto_tree_add_uint(skinny_tree, hf_skinny_srcPort, tvb, offset+12, 4, srcPort);
369 case 0x3 : /* keyPadButtonMessage */
370 dialedDigit = tvb_get_letohl(tvb, offset+12);
372 proto_tree_add_uint(skinny_tree, hf_skinny_dialedDigit, tvb, offset+12, 4, dialedDigit);
376 unknown1 = tvb_get_letohl(tvb, offset+12);
377 unknown2 = tvb_get_letohl(tvb, offset+16);
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);
383 case 0xa : /* speedDialStatReqMessage */
384 line = tvb_get_letohl(tvb, offset+12);
386 proto_tree_add_uint(skinny_tree, hf_skinny_line, tvb, offset+12, 4, line);
389 case 0xb : /* LineStatReqMessage */
390 line = tvb_get_letohl(tvb, offset+12);
392 proto_tree_add_uint(skinny_tree, hf_skinny_line, tvb, offset+12, 4, line);
395 case 0x10 : /* capabilitiesResMessage ===== LOTS to decode here, check jtapi */
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);
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);
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);
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);
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);
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);
436 case 0x2b : /* unknownClientMessage1 */
437 unknown1 = tvb_get_letohl(tvb, offset+12);
439 proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
442 case 0x2d : /* unknownClientMessage2 */
443 unknown1 = tvb_get_letohl(tvb, offset+12);
445 proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
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);
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);
460 case 0x82 : /* startTone */
461 unknown1 = tvb_get_letohl(tvb, offset+12);
463 proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
467 unknown1 = tvb_get_letohl(tvb, offset+12);
469 proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
473 unknown1 = tvb_get_letohl(tvb, offset+12);
474 unknown2 = tvb_get_letohl(tvb, offset+16);
475 unknown3 = tvb_get_letohl(tvb, offset+20);
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);
483 unknown1 = tvb_get_letohl(tvb, offset+12);
485 proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
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);
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);
512 case 0x8b : /* stopMediaTransmission */
513 unknown1 = tvb_get_letohl(tvb, offset+12);
514 unknown2 = tvb_get_letohl(tvb, offset+16);
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);
520 case 0x91 : /* speedDialStatMessage */
521 line = tvb_get_letohl(tvb, offset+12);
523 proto_tree_add_uint(skinny_tree, hf_skinny_line, tvb, offset+12, 4, line);
526 case 0x92 : /* lineStatMessage */
527 line = tvb_get_letohl(tvb, offset+12);
529 proto_tree_add_uint(skinny_tree, hf_skinny_line, tvb, offset+12, 4, line);
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);
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);
554 case 0x97 : /* buttonTemplateMessage === LOTS here check jtapi for hints */
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);
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);
566 case 0x9f : /* reset */
567 unknown1 = tvb_get_letohl(tvb, offset+12);
569 proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
572 case 0x106 : /* closeReceiveChannel */
573 unknown1 = tvb_get_letohl(tvb, offset+12);
574 unknown2 = tvb_get_letohl(tvb, offset+16);
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);
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);
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);
597 memset(extension, '\0', extensionLength);
598 tvb_get_nstringz0(tvb, offset+12, extensionLength, extension);
599 callIdentifier = tvb_get_letohl(tvb, offset+36);
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);
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);
609 unknown2 = tvb_get_letohl(tvb, offset+16);
610 proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+16, 4, unknown2);
612 unknown3 = tvb_get_letohl(tvb, offset+20);
613 proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+20, 4, unknown3);
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);
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);
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);
644 unknown1 = tvb_get_letohl(tvb, offset+12);
645 unknown2 = tvb_get_letohl(tvb, offset+16);
646 callIdentifier = tvb_get_letohl(tvb, offset+20);
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);
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);
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);
667 callIdentifier = tvb_get_letohl(tvb, offset+16);
668 proto_tree_add_uint(skinny_tree, hf_skinny_callIdentifier, tvb, offset+16, 4, callIdentifier);
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);
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);
690 unknown1 = tvb_get_letohl(tvb, offset+12);
692 proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
695 case 0x118 : /* unregisterAckMessage */
696 unknown1 = tvb_get_letohl(tvb, offset+12);
698 proto_tree_add_uint(skinny_tree, hf_skinny_unknown, tvb, offset+12, 4, unknown1);
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);
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);
726 unknown1 = tvb_get_letohl(tvb, offset+36);
727 callIdentifier = tvb_get_letohl(tvb, offset+40);
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);
739 offset = offset + hdr_data_length+8;
743 /* Register the protocol with Ethereal */
745 proto_register_skinny(void)
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.",
756 { &hf_skinny_reserved,
757 { "Reserved", "skinny.reserved",
758 FT_UINT32, BASE_HEX, NULL, 0x0,
759 "Reserved for furture(?) use.",
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.",
770 { &hf_skinny_callIdentifier,
771 { "Call Identifier", "skinny.callIdentifier",
772 FT_UINT32, BASE_DEC, NULL, 0x0,
773 "Call identifier for this call.",
777 { &hf_skinny_packetsSent,
778 { "Packets Sent", "skinny.packetsSent",
779 FT_UINT32, BASE_DEC, NULL, 0x0,
780 "Packets Sent during the call.",
784 { &hf_skinny_octetsSent,
785 { "Octets Sent", "skinny.octetsSent",
786 FT_UINT32, BASE_DEC, NULL, 0x0,
787 "Octets sent during the call.",
791 { &hf_skinny_packetsRecv,
792 { "Packets Received", "skinny.packetsRecv",
793 FT_UINT32, BASE_DEC, NULL, 0x0,
794 "Packets received during the call.",
799 { &hf_skinny_octetsRecv,
800 { "Octets Received", "skinny.octetsRecv",
801 FT_UINT32, BASE_DEC, NULL, 0x0,
802 "Octets received during the call.",
807 { &hf_skinny_packetsLost,
808 { "Packets Lost", "skinny.packetsLost",
809 FT_UINT32, BASE_DEC, NULL, 0x0,
810 "Packets lost during the call.",
815 { &hf_skinny_latency,
816 { "Latency(ms)", "skinny.latency",
817 FT_UINT32, BASE_DEC, NULL, 0x0,
818 "Average packet latency during the call.",
823 { "Jitter", "skinny.jitter",
824 FT_UINT32, BASE_DEC, NULL, 0x0,
825 "Average jitter during the call.",
829 { &hf_skinny_extension,
830 { "Extension", "skinny.extension",
831 FT_STRING, BASE_NONE, NULL, 0x0,
832 "The extension this packets is for.",
836 { &hf_skinny_displayMessage,
837 { "Text", "skinny.displayMessage",
838 FT_STRING, BASE_NONE, NULL, 0x0,
839 "The message displayed on the phone.",
843 { &hf_skinny_timeStamp,
844 { "Timestamp", "skinny.timeStamp",
845 FT_UINT32, BASE_DEC, NULL, 0x0,
846 "Time stamp for the call reference",
850 { &hf_skinny_unknown,
851 { "Unknown Long", "skinny.unknown",
852 FT_UINT32, BASE_HEX, NULL, 0x0,
853 "An as yet undecoded long value",
858 { "IP Source", "skinny.ipSrc",
859 FT_IPv4, BASE_NONE, NULL, 0x0,
865 { "IP Destination", "skinny.ipDest",
866 FT_IPv4, BASE_NONE, NULL, 0x0,
867 "IP destination address",
871 { &hf_skinny_dateYear,
872 { "Year", "skinny.year",
873 FT_UINT32, BASE_DEC, NULL, 0x0,
878 { &hf_skinny_dateMonth,
879 { "Month", "skinny.month",
880 FT_UINT32, BASE_DEC, NULL, 0x0,
885 { &hf_skinny_dateDay,
886 { "Day", "skinny.day",
887 FT_UINT32, BASE_DEC, NULL, 0x0,
888 "The day of the current month",
892 { &hf_skinny_dateHour,
893 { "Hour", "skinny.hour",
894 FT_UINT32, BASE_DEC, NULL, 0x0,
899 { &hf_skinny_dateMinute,
900 { "Minute", "skinny.minute",
901 FT_UINT32, BASE_DEC, NULL, 0x0,
906 { &hf_skinny_destPort,
907 { "Destination Port", "skinny.destPort",
908 FT_UINT32, BASE_DEC, NULL, 0x0,
913 { &hf_skinny_srcPort,
914 { "Source Port", "skinny.srcPort",
915 FT_UINT32, BASE_DEC, NULL, 0x0,
920 { &hf_skinny_softKeyNumber,
921 { "SoftKey", "skinny.softKeyNumber",
922 FT_UINT32, BASE_DEC, NULL, 0x0,
927 { &hf_skinny_dialedDigit,
928 { "Dialed Digit", "skinny.dialedDigit",
929 FT_UINT32, BASE_DEC, NULL, 0x0,
935 { "Line", "skinny.line",
936 FT_UINT32, BASE_DEC, NULL, 0x0,
943 /* Setup protocol subtree array */
944 static gint *ett[] = {
948 /* Register the protocol name and description */
949 proto_skinny = proto_register_protocol("Skinny Client Control Protocol",
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));
958 proto_reg_handoff_skinny(void)
960 dissector_handle_t skinny_handle;
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);