2 * Routines for PTP/IP (Picture Transfer Protocol) packet dissection
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 * [1] CIPA DC-X005-2005 - PTP-IP
29 * [2] BS ISO 15740:2008 - Photography Electronic still picture imaging - Picture transfer protocol (PTP)
30 * for digital still photography devices
31 * [3] gPhoto's Reversed Engineered PTP/IP documentation - http://gphoto.sourceforge.net/doc/ptpip.php
32 * [4] gPhoto's ptp2 header file https://gphoto.svn.sourceforge.net/svnroot/gphoto/trunk/libgphoto2/camlibs/ptp2/ptp.h
34 * @todo: This is being written as 1 dissector when in reality there is PTP/IP and PTP. Future work should include splitting this into 2
35 * so that the PTP layer may be used again for PTP/USB.
37 #include "packet-ptpip.h"
43 #include <epan/packet.h>
47 #define PTPIP_PORT 15740 /*[1] Section 2.2.3.1*/
48 #define PTPIP_GUID_SIZE 16 /*[1] Section 2.3.1*/
49 #define PTPIP_MAX_PARAM_COUNT 5 /*[1] Section 2.3.6*/
52 static gint ett_ptpIP
= -1;
53 static gint ett_ptpIP_hdr
= -1;
57 static int proto_ptpIP
= -1;
58 static int hf_ptpIP_len
= -1; /*[1] Section 2.3*/
59 static int hf_ptpIP_pktType
= -1; /*[1] Section 2.3*/
60 static int hf_ptpIP_guid
= -1;
61 static int hf_ptpIP_name
= -1;
62 static int hf_ptpIP_version
= -1;
63 static int hf_ptpIP_connectionNumber
= -1;
64 static int hf_ptpIP_dataPhaseInfo
= -1;
66 /*note: separating the fields to make it easier to divide this code later.*/
69 /*picking hf_ptp for now. Might need to change later for namespace issues with Precision Time Protocol.*/
70 static int hf_ptp_opCode
= -1;
71 static int hf_ptp_respCode
= -1;
72 static int hf_ptp_eventCode
= -1;
73 static int hf_ptp_transactionID
= -1;
74 static int hf_ptp_totalDataLength
= -1;
75 static int hf_ptp_opCode_param_sessionID
= -1;
77 /* function declarations */
78 static int dissect_ptpIP (tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
);
79 void dissect_ptpIP_init_command_request(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
);
80 void dissect_ptpIP_init_command_ack(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
);
81 void dissect_ptpIP_init_event_request(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
);
82 void dissect_ptpIP_init_event_ack(packet_info
*pinfo
);
83 void dissect_ptpIP_operation_request(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
);
84 void dissect_ptpIP_operation_response(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
);
85 void dissect_ptpIP_start_data(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
);
86 void dissect_ptpIP_data(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
);
87 void dissect_ptpIP_end_data(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
);
88 void dissect_ptpIP_event(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
);
89 void dissect_ptpIP_unicode_name(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
);
90 void dissect_ptpIP_protocol_version(tvbuff_t
*tvb
, proto_tree
*tree
, guint16
*offset
);
91 void dissect_ptpIP_guid(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
);
92 void proto_register_ptpip( void );
93 void proto_reg_handoff_ptpIP( void );
95 /*String Names of packet types [3] & [4]*/
96 /* PTP/IP definitions*/
97 /*enums reformatted from [4]*/
100 PTPIP_INIT_COMMAND_REQUEST
= 1,
101 PTPIP_INIT_COMMAND_ACK
= 2,
102 PTPIP_INIT_EVENT_REQUEST
= 3,
103 PTPIP_INIT_EVENT_ACK
= 4,
105 PTPIP_CMD_REQUEST
= 6, /*possibly Operation request in [1] 2.3.6 agrees with [3]*/
106 PTPIP_CMD_RESPONSE
= 7, /*possibly Operation response in [1] 2.3.7 agrees with [3]*/
108 PTPIP_START_DATA_PACKET
= 9,
109 PTPIP_DATA_PACKET
= 10,
110 PTPIP_CANCEL_TRANSACTION
= 11,
111 PTPIP_END_DATA_PACKET
= 12,
112 PTPIP_PING
= 13, /*possibly Probe Request in [1] 2.3.13*/
113 PTPIP_PONG
= 14 /*possibly Probe Response in [1] 2.3.14*/
116 /*Unless otherwise stated, names are based on info in [3]*/
117 static const value_string ptpip_pktType_names
[] = {
118 { PTPIP_INIT_COMMAND_REQUEST
, "Init Command Request Packet" },
119 { PTPIP_INIT_COMMAND_ACK
, "Init Command ACK Packet" },
120 { PTPIP_INIT_EVENT_REQUEST
, "Init Event Request Packet" },
121 { PTPIP_INIT_EVENT_ACK
, "Init Event Ack Packet"},
122 { PTPIP_INIT_FAIL
, "Init Fail Packet"},
123 { PTPIP_CMD_REQUEST
, "Operation Request Packet"}, /* string based on [1]*/
124 { PTPIP_CMD_RESPONSE
, "Operation Response Packet"}, /*string based on [1]*/
125 { PTPIP_EVENT
, "Event Packet"},
126 { PTPIP_START_DATA_PACKET
, "Start Data Packet"},
127 { PTPIP_DATA_PACKET
, "Data Packet"},
128 { PTPIP_CANCEL_TRANSACTION
, "Cancel Packet"},
129 { PTPIP_END_DATA_PACKET
, "End Data Packet"},
130 { PTPIP_PING
, "Probe Request Packet"}, /* string based on [1]*/
131 { PTPIP_PONG
, "Probe Response Packet"}, /* string based on [1]*/
132 { PTPIP_INVALID
, "Invalid" },
138 * Primary method to dissect a PTP/IP packet. When a subtype is encounter,
139 * the method will call a subdissector.
142 int dissect_ptpIP (tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
144 proto_item
*item_ptr
;
145 proto_tree
*ptp_tree
;
150 /* Check that there's enough data */
151 if ( tvb_length_remaining(tvb
, offset
) < 8 ) /* ptp-photo smallest packet size is 8 */
154 col_set_str(pinfo
->cinfo
,COL_PROTOCOL
, "PTP/IP");
159 "Picture Transfer Protocol");
161 item_ptr
= proto_tree_add_protocol_format(tree
, proto_ptpIP
, tvb
, offset
,
162 -1, "Picture Transfer Protocol");
164 /*creating the tree*/
165 ptp_tree
= proto_item_add_subtree(item_ptr
, ett_ptpIP
);
166 /*[1] Defines first 2 fields as length and packet type. (Section 2.3)
167 * Also note: the standard lists all multibyte values in PTP-IP as little-endian
170 /* note: len field size included in total len*/
171 proto_tree_add_item(ptp_tree
, hf_ptpIP_len
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
173 /*@todo:maybe add some length verification checks to see if len advertised matches actual len*/
175 pktType
= tvb_get_letohl(tvb
, offset
);
176 proto_tree_add_item(ptp_tree
, hf_ptpIP_pktType
, tvb
, offset
, 4, ENC_LITTLE_ENDIAN
);
179 case PTPIP_INIT_COMMAND_REQUEST
:
180 dissect_ptpIP_init_command_request(tvb
, pinfo
, ptp_tree
, &offset
);
182 case PTPIP_INIT_COMMAND_ACK
:
183 dissect_ptpIP_init_command_ack(tvb
, pinfo
, ptp_tree
, &offset
);
185 case PTPIP_INIT_EVENT_REQUEST
:
186 dissect_ptpIP_init_event_request(tvb
, pinfo
, ptp_tree
, &offset
);
188 case PTPIP_INIT_EVENT_ACK
:
189 dissect_ptpIP_init_event_ack(pinfo
);
191 case PTPIP_CMD_REQUEST
:
192 dissect_ptpIP_operation_request(tvb
, pinfo
, ptp_tree
, &offset
);
194 case PTPIP_CMD_RESPONSE
:
195 dissect_ptpIP_operation_response(tvb
, pinfo
, ptp_tree
, &offset
);
198 dissect_ptpIP_event(tvb
, pinfo
, ptp_tree
, &offset
);
200 case PTPIP_START_DATA_PACKET
:
201 dissect_ptpIP_start_data(tvb
, pinfo
, ptp_tree
, &offset
);
203 case PTPIP_DATA_PACKET
:
204 dissect_ptpIP_data(tvb
, pinfo
, ptp_tree
, &offset
);
206 case PTPIP_END_DATA_PACKET
:
207 dissect_ptpIP_end_data(tvb
, pinfo
, ptp_tree
, &offset
);
217 * Method to dissect the Init Command Request sent by the Initiator
218 * in the connection. This packet is defined by [1] Section 2.3.1
220 void dissect_ptpIP_init_command_request(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
)
227 "Init Command Request");
229 dissect_ptpIP_guid(tvb
, pinfo
, tree
, offset
);
231 /*grabbing the name*/
232 dissect_ptpIP_unicode_name(tvb
, pinfo
, tree
, offset
);
234 /*grabbing protocol version
235 * Note: [3] does not list this in the packet field. . [1] 2.3.1 states its the last 4
236 * bytes of the packet.
238 dissect_ptpIP_protocol_version(tvb
, tree
, offset
);
243 * Method to dissect the Init Command Ack sent by the Responder
244 * in the connection. This packet is defined by [1] Section 2.3.2
246 void dissect_ptpIP_init_command_ack(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
)
248 guint32 connectionNumber
;
255 /*Grabbing the Connection Number*/
256 connectionNumber
= tvb_get_letohl(tvb
, *offset
);
257 proto_tree_add_item(tree
, hf_ptpIP_connectionNumber
, tvb
, *offset
, 4,ENC_LITTLE_ENDIAN
);
265 dissect_ptpIP_guid(tvb
, pinfo
, tree
, offset
);
268 dissect_ptpIP_unicode_name(tvb
,pinfo
, tree
, offset
);
270 /*grabbing protocol version. Note: like in the Init Command Request, [3] doesn't mention
271 * this field, but [1] Section 2.3.2 does.
273 dissect_ptpIP_protocol_version(tvb
, tree
, offset
);
277 * Dissects the Init Event Request packet specified in [1] Section 2.3.3.
278 * Standard states that the packet only has 1 field.
280 void dissect_ptpIP_init_event_request(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
)
282 guint32 connectionNumber
;
287 "Init Event Request");
289 /*Grabbing the Connection Number*/
290 connectionNumber
= tvb_get_letohl(tvb
, *offset
);
291 proto_tree_add_item(tree
, hf_ptpIP_connectionNumber
, tvb
, *offset
, 4,ENC_LITTLE_ENDIAN
);
301 * Dissects the Init Event Ack packet specified in [1] Section 2.3.4
303 void dissect_ptpIP_init_event_ack(packet_info
*pinfo
)
310 /*packet has no payload.*/
314 * Dissects the Operation Request Packet specified in [1] Section 2.3.6
315 * Note: many of the fields in this packet move from PTP/IP to PTP layer
316 * of the stack. Work will need to be done in future iterations to make this
317 * compatible with PTP/USB.
319 void dissect_ptpIP_operation_request(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
)
322 guint16 transactionID_offset
= *offset
; /*need to save this to output transaction id in pinfo*/
327 "Operation Request Packet ");
329 proto_tree_add_item(tree
,hf_ptpIP_dataPhaseInfo
, tvb
, *offset
, 4, ENC_LITTLE_ENDIAN
);
332 opcode
= tvb_get_letohs(tvb
, *offset
);
333 proto_tree_add_item(tree
, hf_ptp_opCode
, tvb
, *offset
, 2, ENC_LITTLE_ENDIAN
);
336 transactionID_offset
= *offset
; /*we'll dissect the transactionID later because opcode handling erases the column*/
339 /*carving out the parameters. [1] 2.3.6 states there can be at most 5. Params are defined in [2] 10.1 & 10.4*/
342 case PTP_OC_GetDeviceInfo
:
350 case PTP_OC_OpenSession
:
351 dissect_ptp_opCode_openSession(tvb
, pinfo
, tree
, offset
);
353 case PTP_OC_CloseSession
:
361 case PTP_OC_GetStorageIDs
:
367 /*states data is a storage array. Needs eventual investigation.*/
372 dissect_ptp_transactionID(tvb
, pinfo
, tree
, &transactionID_offset
);
376 * Dissects the Operation Response Packet specified in [1] Section 2.3.7
377 * Note: many of the fields in this packet move from PTP/IP to PTP layer
378 * of the stack. Work will need to be done in future iterations to make this
379 * compatible with PTP/USB.
381 void dissect_ptpIP_operation_response(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
)
386 "Operation Response Packet ");
388 proto_tree_add_item(tree
, hf_ptp_respCode
, tvb
, *offset
, 2, ENC_LITTLE_ENDIAN
);
391 dissect_ptp_transactionID(tvb
, pinfo
, tree
, offset
);
396 * Dissects the Event Packet specified in [1] Section 2.3.8
397 * Note: many of the fields in this packet move from PTP/IP to PTP layer
398 * of the stack. Work will need to be done in future iterations to make this
399 * compatible with PTP/USB.
401 void dissect_ptpIP_event(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
)
408 proto_tree_add_item(tree
, hf_ptp_eventCode
, tvb
, *offset
, 2, ENC_LITTLE_ENDIAN
);
411 dissect_ptp_transactionID(tvb
, pinfo
, tree
, offset
);
415 * Dissects the Event Packet specified in [1] Section 2.3.9
416 * Note: many of the fields in this packet move from PTP/IP to PTP layer
417 * of the stack. Work will need to be done in future iterations to make this
418 * compatible with PTP/USB.
420 void dissect_ptpIP_start_data(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
)
427 "Start Data Packet ");
429 dissect_ptp_transactionID(tvb
, pinfo
, tree
, offset
);
432 dataLen
= tvb_get_letoh64(tvb
, *offset
);
433 proto_tree_add_item(tree
, hf_ptp_totalDataLength
, tvb
, *offset
, 8, ENC_LITTLE_ENDIAN
);
435 if(dataLen
== G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF)) /*[1] specifies in 2.3.9 if total data len this value then len unknown*/
440 " Data Length Unknown");
444 void dissect_ptpIP_data(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
)
452 dissect_ptp_transactionID(tvb
, pinfo
, tree
, offset
);
457 * Dissects the End Data specified in [1] Section 2.3.11
458 * Note: many of the fields in this packet move from PTP/IP to PTP layer
459 * of the stack. Work will need to be done in future iterations to make this
460 * compatible with PTP/USB.
462 void dissect_ptpIP_end_data(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
)
470 dissect_ptp_transactionID(tvb
, pinfo
, tree
, offset
);
474 * Dissects the Opcode Open Session as defined by [2] 10.5.2
476 void dissect_ptp_opCode_openSession(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
)
483 proto_tree_add_item(tree
, hf_ptp_opCode_param_sessionID
, tvb
, *offset
, 4 , ENC_LITTLE_ENDIAN
);
488 * The transaction ID is defined in [2] 9.3.1
489 * and used in multiple message types. This method handles
490 * parsing the field and adding the value to the info
494 void dissect_ptp_transactionID(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
)
496 guint32 transactionID
;
498 transactionID
= tvb_get_letohl(tvb
, *offset
);
499 proto_tree_add_item(tree
, hf_ptp_transactionID
, tvb
, *offset
, 4, ENC_LITTLE_ENDIAN
);
504 " Transaction ID: %d",
509 * This method handles dissecting the Unicode name that is
510 * specificed in multiple packets.
512 void dissect_ptpIP_unicode_name(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
)
517 nameLen
= tvb_unicode_strsize(tvb
, *offset
);
518 name
= tvb_get_unicode_string(wmem_packet_scope(), tvb
, *offset
, nameLen
, ENC_LITTLE_ENDIAN
);
519 proto_tree_add_unicode_string(tree
, hf_ptpIP_name
, tvb
, *offset
, nameLen
, name
);
528 /** Method dissects the protocol version from the packets.
529 * Additional note, section 3 of [1] defines the Binary Protocol version
530 * as 0x00010000 == 1.0 where the Most significant bits are the major version and the least
531 * significant bits are the minor version.
533 void dissect_ptpIP_protocol_version(tvbuff_t
*tvb
, proto_tree
*tree
, guint16
*offset
)
537 guint32 protoVersion
;
538 guint16 majorVersion
, minorVersion
;
540 protoVersion
= tvb_get_letohl(tvb
, *offset
);
541 /*logic to format version*/
542 minorVersion
= protoVersion
& 0xFFFF;
543 majorVersion
= (protoVersion
& 0xFFFF0000) >>16;
544 g_snprintf(version
, 30, "%u.%u", majorVersion
, minorVersion
);
545 proto_tree_add_string(tree
, hf_ptpIP_version
, tvb
, *offset
, 4, version
);
549 /*Grabbing the GUID*/
550 void dissect_ptpIP_guid(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, guint16
*offset
)
554 guid
= tvb_bytes_to_str(tvb
, *offset
, PTPIP_GUID_SIZE
);
555 proto_tree_add_item(tree
, hf_ptpIP_guid
, tvb
, *offset
, PTPIP_GUID_SIZE
, ENC_NA
);
556 *offset
+= PTPIP_GUID_SIZE
;
564 void proto_register_ptpip( void )
566 static hf_register_info hf
[] = {
569 "Length", "ptpip.len", FT_UINT32
, BASE_DEC
,
570 NULL
, 0, NULL
, HFILL
}},
571 { &hf_ptpIP_pktType
, {
572 "Packet Type", "ptpip.pktType", FT_UINT32
, BASE_HEX
,
573 VALS(ptpip_pktType_names
), 0, NULL
, HFILL
}},
575 "GUID", "ptpip.guid", FT_BYTES
, BASE_NONE
,
576 NULL
, 0, NULL
, HFILL
}},
578 "Host Name", "ptpip.name", FT_STRINGZ
, BASE_NONE
,
579 NULL
, 0, NULL
, HFILL
}},
580 { &hf_ptpIP_version
, {
581 "Version", "ptpip.version", FT_STRING
, BASE_NONE
,
582 NULL
, 0, NULL
, HFILL
}},
583 { &hf_ptpIP_connectionNumber
, {
584 "Connection Number", "ptpip.connection", FT_UINT32
, BASE_DEC
,
585 NULL
, 0, NULL
, HFILL
}},
586 { &hf_ptpIP_dataPhaseInfo
, {
587 "Data Phase Info", "ptpip.phaseinfo", FT_UINT32
, BASE_HEX
,
588 NULL
, 0, NULL
, HFILL
}},
590 /*leaving names with "ptpip" to try and prevent namespace issues. probably changing later.*/
592 "Operation Code", "ptpip.opcode", FT_UINT16
, BASE_HEX
,
593 VALS(ptp_opcode_names
), 0, NULL
, HFILL
}},
594 { &hf_ptp_respCode
, {
595 "Response Code", "ptpip.respcode", FT_UINT16
, BASE_HEX
,
596 VALS(ptp_respcode_names
), 0, NULL
, HFILL
}},
597 { &hf_ptp_eventCode
, {
598 "Event Code", "ptpip.eventcode", FT_UINT16
, BASE_HEX
,
599 NULL
, 0, NULL
, HFILL
}},
600 { &hf_ptp_transactionID
, {
601 "Transaction ID", "ptpip.transactionID", FT_UINT32
, BASE_HEX
,
602 NULL
, 0, NULL
, HFILL
}},
603 { &hf_ptp_totalDataLength
, {
604 "Total Data Length", "ptpip.datalen", FT_UINT64
, BASE_DEC_HEX
,
605 NULL
, 0, NULL
, HFILL
}},
606 { &hf_ptp_opCode_param_sessionID
, {
607 "Session ID", "ptpip.opcode.param.sessionid", FT_UINT32
, BASE_HEX
,
608 NULL
, 0, NULL
, HFILL
}},
611 static gint
*ett
[] = {
616 proto_ptpIP
= proto_register_protocol("Picture Transfer Protocol Over IP", "PTP/IP", "ptpip");
618 proto_register_field_array(proto_ptpIP
, hf
, array_length(hf
));
619 proto_register_subtree_array(ett
, array_length(ett
));
622 void proto_reg_handoff_ptpIP( void ) {
624 dissector_handle_t ptpIP_handle
;
626 /* Use new_create_dissector_handle() to indicate that dissect_wol()
627 * returns the number of bytes it dissected (or 0 if it thinks the packet
628 * does not belong to PROTONAME).
631 ptpIP_handle
= new_create_dissector_handle(dissect_ptpIP
, proto_ptpIP
);
632 dissector_add_uint("tcp.port", PTPIP_PORT
, ptpIP_handle
);