Skip to content

Instantly share code, notes, and snippets.

@codestation
Created January 7, 2014 23:24
Show Gist options
  • Save codestation/8308794 to your computer and use it in GitHub Desktop.
Save codestation/8308794 to your computer and use it in GitHub Desktop.
-- Copyright 2014 codestation
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
local vitaptp_proto = Proto("PSVITA_PTP-IP","PS Vita PTP-IP")
vitaptp_proto.prefs["tcp_port"] = Pref.uint("TCP Port", 999, "TCP Port for PS Vita PTP/IP")
ptp_container_types = {
[1] = "PTPIP_INIT_COMMAND_REQUEST",
[2] = "PTPIP_INIT_COMMAND_ACK",
[3] = "PTPIP_INIT_EVENT_REQUEST",
[4] = "PTPIP_INIT_EVENT_ACK",
[5] = "PTPIP_INIT_FAIL",
[6] = "PTPIP_CMD_REQUEST",
[7] = "PTPIP_CMD_RESPONSE",
[8] = "PTPIP_EVENT",
[9] = "PTPIP_START_DATA_PACKET",
[10] = "PTPIP_DATA_PACKET",
[11] = "PTPIP_CANCEL_TRANSACTION",
[12] = "PTPIP_END_DATA_PACKET",
[13] = "PTPIP_PING",
[14] = "PTPIP_PONG",
}
ptp_operation_codes = {
[0x1002] = "PTP_OC_OpenSession",
[0x100C] = "PTP_OC_SendObjectInfo",
[0x100D] = "PTP_OC_SendObject",
[0x9511] = "PTP_OC_VITA_GetVitaInfo",
[0x9513] = "PTP_OC_VITA_SendNumOfObject",
[0x9514] = "PTP_OC_VITA_GetBrowseInfo",
[0x9515] = "PTP_OC_VITA_SendObjectMetadata",
[0x9516] = "PTP_OC_VITA_SendObjectThumb",
[0x9518] = "PTP_OC_VITA_ReportResult",
[0x951C] = "PTP_OC_VITA_SendInitiatorInfo",
[0x951F] = "PTP_OC_VITA_GetUrl",
[0x9520] = "PTP_OC_VITA_SendHttpObjectFromURL",
[0x9523] = "PTP_OC_VITA_SendNPAccountInfo",
[0x9524] = "PTP_OC_VITA_GetSettingInfo",
[0x9528] = "PTP_OC_VITA_SendObjectStatus",
[0x9529] = "PTP_OC_VITA_SendHttpObjectPropFromURL",
[0x952A] = "PTP_OC_VITA_SendHostStatus",
[0x952B] = "PTP_OC_VITA_SendPartOfObjectInit",
[0x952C] = "PTP_OC_VITA_SendPartOfObject",
[0x952E] = "PTP_OC_VITA_OperateObject",
[0x952F] = "PTP_OC_VITA_GetPartOfObject",
[0x9533] = "PTP_OC_VITA_SendStorageSize",
[0x9534] = "PTP_OC_VITA_GetTreatObject",
[0x9535] = "PTP_OC_VITA_SendCopyConfirmationInfo",
[0x9536] = "PTP_OC_VITA_SendObjectMetadataItems",
[0x9537] = "PTP_OC_VITA_SendCopyConfirmationInfoInit",
[0x9538] = "PTP_OC_VITA_KeepAlive",
[0x953A] = "PTP_OC_VITA_Unknown1",
[0x953B] = "PTP_OC_VITA_GetVitaCapabilityInfo",
[0x953C] = "PTP_OC_VITA_SendPCCapabilityInfo",
}
ptp_response_codes = {
[0x2000] = "PTP_RC_Undefined",
[0x2001] = "PTP_RC_OK",
[0x2002] = "PTP_RC_GeneralError",
[0x2003] = "PTP_RC_SessionNotOpen",
[0x2004] = "PTP_RC_InvalidTransactionID",
[0x2005] = "PTP_RC_OperationNotSupported",
[0x2006] = "PTP_RC_ParameterNotSupported",
[0x2007] = "PTP_RC_IncompleteTransfer",
[0x2008] = "PTP_RC_InvalidStorageId",
[0x2009] = "PTP_RC_InvalidObjectHandle",
[0x200A] = "PTP_RC_DevicePropNotSupported",
[0x200B] = "PTP_RC_InvalidObjectFormatCode",
[0x200C] = "PTP_RC_StoreFull",
[0x200D] = "PTP_RC_ObjectWriteProtected",
[0x200E] = "PTP_RC_StoreReadOnly",
[0x200F] = "PTP_RC_AccessDenied",
[0x2010] = "PTP_RC_NoThumbnailPresent",
[0x2011] = "PTP_RC_SelfTestFailed",
[0x2012] = "PTP_RC_PartialDeletion",
[0x2013] = "PTP_RC_StoreNotAvailable",
[0x2014] = "PTP_RC_SpecificationByFormatUnsupported",
[0x2015] = "PTP_RC_NoValidObjectInfo",
[0x2016] = "PTP_RC_InvalidCodeFormat",
[0x2017] = "PTP_RC_UnknownVendorCode",
[0x2018] = "PTP_RC_CaptureAlreadyTerminated",
[0x2019] = "PTP_RC_DeviceBusy",
[0x201A] = "PTP_RC_InvalidParentObject",
[0x201B] = "PTP_RC_InvalidDevicePropFormat",
[0x201C] = "PTP_RC_InvalidDevicePropValue",
[0x201D] = "PTP_RC_InvalidParameter",
[0x201E] = "PTP_RC_SessionAlreadyOpened",
[0x201F] = "PTP_RC_TransactionCanceled",
[0xA001] = "PTP_RC_VITA_Invalid_Context",
}
ptp_event_codes = {
[0xC104] = "PTP_EC_VITA_RequestSendNumOfObject",
[0xC105] = "PTP_EC_VITA_RequestSendObjectMetadata",
[0xC107] = "PTP_EC_VITA_RequestSendObject",
[0xC108] = "PTP_EC_VITA_RequestCancelTask",
[0xC10B] = "PTP_EC_VITA_RequestSendHttpObjectFromURL",
[0xC10D] = "PTP_EC_VITA_Unknown1",
[0xC10F] = "PTP_EC_VITA_RequestSendObjectStatus",
[0xC110] = "PTP_EC_VITA_RequestSendObjectThumb",
[0xC111] = "PTP_EC_VITA_RequestDeleteObject",
[0xC112] = "PTP_EC_VITA_RequestGetSettingInfo",
[0xC113] = "PTP_EC_VITA_RequestSendHttpObjectPropFromURL",
[0xC115] = "PTP_EC_VITA_RequestSendPartOfObject",
[0xC117] = "PTP_EC_VITA_RequestOperateObject",
[0xC118] = "PTP_EC_VITA_RequestGetPartOfObject",
[0xC119] = "PTP_EC_VITA_RequestSendStorageSize",
[0xC120] = "PTP_EC_VITA_RequestCheckExistance",
[0xC122] = "PTP_EC_VITA_RequestGetTreatObject",
[0xC123] = "PTP_EC_VITA_RequestSendCopyConfirmationInfo",
[0xC124] = "PTP_EC_VITA_RequestSendObjectMetadataItems",
[0xC125] = "PTP_EC_VITA_RequestSendNPAccountInfo",
[0xC126] = "PTP_EC_VITA_RequestTerminate",
}
local fields = vitaptp_proto.fields
fields.container_length = ProtoField.uint32("ptp.container.length", "Container Length", base.DEC)
fields.container_type = ProtoField.uint32("ptp.container.type", "Container Type", nil, ptp_container_types)
fields.operation_code = ProtoField.uint16("ptp.operation.code", "Operation Code", base.HEX, ptp_operation_codes)
fields.response_code = ProtoField.uint16("ptp.response.code", "Response Code", base.HEX, ptp_response_codes)
fields.event_code = ProtoField.uint16("ptp.event.code", "Event Code", base.HEX, ptp_event_codes)
fields.failure_code = ProtoField.uint16("ptp.failure.code", "Failure Code", base.HEX)
fields.transaction_id = ProtoField.uint32("ptp.transaction.id", "Transaction ID", base.DEC)
fields.payload = ProtoField.bytes("ptp.payload", "Payload")
fields.intiator_guid = ProtoField.guid("ptp.initiator.guid", "Initiator GUID")
fields.intiator_name = ProtoField.string("ptp.initiator.name", "Initiator Friendly Name")
fields.intiator_proto_version = ProtoField.uint32("ptp.initiator.protocol_version", "Initiator Protocol Version", base.HEX)
fields.session_id = ProtoField.uint32("ptp.session.id", "Connection Number")
fields.responder_guid = ProtoField.guid("ptp.responder.guid", "Responder GUID")
fields.responder_name = ProtoField.string("ptp.responder.name", "Responder Friendly Name")
fields.responder_proto_version = ProtoField.uint32("ptp.responder.protocol_version", "Initiator Protocol Version", base.HEX)
fields.dataphase = ProtoField.uint32("ptp.dataphase", "Dataphase", base.HEX)
fields.data_length = ProtoField.uint64("ptp.data_length", "Data Length")
local ptp_container_dispatch = {
-- Init Command Request
[1] = function (buffer, subtree)
subtree:add(fields.intiator_guid, buffer(0, 16))
end,
-- Init Command ACK
[2] = function (buffer, subtree)
subtree:add(fields.session_id, buffer(0, 4):le_uint())
end,
-- Init Event Request
[3] = function (buffer, subtree)
subtree:add(fields.session_id, buffer(0, 4):le_uint())
end,
-- Init Event ACK
[4] = function (buffer, subtree)
end,
-- Init Fail
[5] = function (buffer, subtree)
local failure_code = buffer(6, 4):le_uint()
subtree:add(fields.failure_code, failure_code)
return string.format("%04X", failure_code)
end,
-- Operation Request
[6] = function (buffer, subtree)
local op_code = buffer(4, 2):le_uint()
local transaction_id = buffer(6, 4):le_uint()
subtree:add(fields.dataphase, buffer(0, 4):le_uint())
subtree:add(fields.operation_code, op_code)
subtree:add(fields.transaction_id, transaction_id)
if ptp_operation_codes[op_code] ~= nil then
return ptp_operation_codes[op_code] .. " (Transaction #" .. transaction_id .. ")"
else
return string.format("%04X (Transaction #%d)", op_code, transaction_id)
end
end,
-- Operation Response
[7] = function (buffer, subtree)
local response_code = buffer(0, 2):le_uint()
local transaction_id = buffer(2, 4):le_uint()
subtree:add(fields.response_code, response_code)
subtree:add(fields.transaction_id, transaction_id)
if ptp_response_codes[response_code] ~= nil then
return ptp_response_codes[response_code] .. " (Transaction #" .. transaction_id .. ")"
else
return string.format("%04X (Transaction #%d)", response_code, transaction_id)
end
end,
-- Event
[8] = function (buffer, subtree)
local event_code = buffer(0, 2):le_uint()
local transaction_id = buffer(2, 4):le_uint()
subtree:add(fields.event_code, event_code)
subtree:add(fields.transaction_id, transaction_id)
if ptp_event_codes[event_code] ~= nil then
return ptp_event_codes[event_code] .. " (Transaction #" .. transaction_id .. ")"
else
return string.format("%04X (Transaction #%d)", event_code, transaction_id)
end
end,
-- Start Data
[9] = function (buffer, subtree)
local transaction_id = buffer(0, 4):le_uint()
subtree:add(fields.transaction_id, transaction_id)
subtree:add(fields.data_length, buffer(4, 8):le_uint64())
-- added payload
subtree:add(fields.payload, buffer(8))
return "Transaction #" .. transaction_id
end,
-- Data
[10] = function (buffer, subtree)
local transaction_id = buffer(0, 4):le_uint()
subtree:add(fields.transaction_id, transaction_id)
subtree:add(fields.payload, buffer(4))
return "Transaction #" .. transaction_id
end,
-- End Data
[11] = function (buffer, subtree)
local transaction_id = buffer(0, 4):le_uint()
subtree:add(fields.transaction_id, transaction_id)
-- added payload
subtree:add(fields.payload, buffer(4))
return "Transaction #" .. transaction_id
end,
-- Cancel
[12] = function (buffer, subtree)
local transaction_id = buffer(0, 4):le_uint()
subtree:add(fields.transaction_id, transaction_id)
subtree:add(fields.payload, buffer(4))
return "Transaction #" .. transaction_id
end,
}
local CONTAINER_HEADER_LENGTH = 8
function vitaptp_proto.init()
local tcp_table = DissectorTable.get("tcp.port")
tcp_table:add(vitaptp_proto.prefs["tcp_port"], vitaptp_proto)
end
function vitaptp_proto.dissector(buffer, pinfo, tree)
local remaining = buffer:len() - CONTAINER_HEADER_LENGTH
if remaining < 0 then
pinfo.desegment_len = -remaining
return remaining
end
local ptp_length = buffer(0, 4):le_uint()
remaining = buffer:len() - ptp_length
if remaining < 0 then
pinfo.desegment_len = -remaining
return remaining
end
pinfo.cols.protocol = "PSVita PTP/IP"
local ptp_type = buffer(4, 4):le_uint()
local subtree = tree:add(vitaptp_proto, buffer(), "PS Vita PTP/IP Protocol")
subtree:add(fields.container_length, ptp_length)
subtree = subtree:add(fields.container_type, ptp_type)
pinfo.cols.info = ptp_container_types[ptp_type]
local dispatch = ptp_container_dispatch[ptp_type]
if dispatch ~= nil then
local infos = dispatch(buffer(CONTAINER_HEADER_LENGTH, ptp_length - CONTAINER_HEADER_LENGTH), subtree)
if infos ~= nil then
pinfo.cols.info:append(": " .. infos)
end
elseif ptp_length > CONTAINER_HEADER_LENGTH then
subtree:add(fields.payload, buffer(CONTAINER_HEADER_LENGTH, ptp_length - CONTAINER_HEADER_LENGTH))
end
return ptp_length
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment