diff --git a/Installer/InstallerScript.iss b/Installer/InstallerScript.iss index 60dd73c..e876ea4 100644 --- a/Installer/InstallerScript.iss +++ b/Installer/InstallerScript.iss @@ -1,5 +1,5 @@ // DO NOT CHANGE VERSION HERE! Run update_version.bat -#define AppVer "1.2.0" +#define AppVer "1.3.0" #define AppId "dsV2Gshark" [Setup] diff --git a/OSSAcknowledgements.txt b/OSSAcknowledgements.txt index fe328ec..3a90136 100644 --- a/OSSAcknowledgements.txt +++ b/OSSAcknowledgements.txt @@ -141,7 +141,7 @@ cbExiGen The license text of the 'Apache License Version 2.0' can be found in APPENDIX A. -Wireshark 4.2.3 +Wireshark 4.2.4 Copyright: Copyright 1998-2024 Gerald Combs and contributors Repository: https://gitlab.com/wireshark/wireshark diff --git a/README.md b/README.md index faf1d96..375a814 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ The plugin processes a TLS master secret disclosure packet after handshake to de The disclosure message is a UDP packet within the source port range 49152-65535 (see Wireshark protocol settings) containing the ASCII string `CLIENT_RANDOM <32-byte client random> <48-byte master secret>` as payload data. This disclosure message has to be sent from one of the communication partners in a testing environment. For TLS 1.3 decryption you have to provide different secrets: `CLIENT_HANDSHAKE_TRAFFIC_SECRET`, `SERVER_HANDSHAKE_TRAFFIC_SECRET`, `EXPORTER_SECRET`, `CLIENT_TRAFFIC_SECRET_`, `SERVER_TRAFFIC_SECRET_`. You can send one UDP packet for each secret or combine the secrets in one UDP packet (separated by line breaks). + ### Wireshark I/O Graph This optional feature updates the Wireshark I/O Graph preferences to display a V2G session. The graph can be accessed via 'Statistics' -> 'I/O Graphs' (shortcut: Alt + S + I). The graph displays the data in 1 second intervals. This can be changed using the drop down menu at the bottom. @@ -57,10 +58,11 @@ Click on a packet in the graph to inspect it in the Wireshark main window. Press ## Limitations - ISO 15118-20 is not fully supported yet - - some BPT messages are not fully decoded + - please let us know if you encounter incorrectly decoded packets - Linux - no installer - filter buttons and color filters must be added manually + - I/O graph must be configured manually ## Support - If you encounter any problems, feel free to open an issue or contact us at support@dSPACE.de @@ -69,7 +71,7 @@ Click on a packet in the graph to inspect it in the Wireshark main window. Press ## Further notes - When sniffing V2G communication, lost packets may occur, which cause corrupted TCP/TLS sessions. In that case, it may help to activate the option to ignore Message Authentication Code (MAC) check failures in the Wireshark TLS protocol settings. This option can be found under Wireshark Preferences - Protocols - TLS -- This plugin was built and tested with Wireshark 4.2.3 +- This plugin was built and tested with Wireshark 4.2.4 - The EXI decoding is based on [cbExiGen](https://github.com/EVerest/cbexigen) diff --git a/V2G_Libraries/CertificateInfos/main.rc b/V2G_Libraries/CertificateInfos/main.rc index 113b220..18f978f 100644 --- a/V2G_Libraries/CertificateInfos/main.rc +++ b/V2G_Libraries/CertificateInfos/main.rc @@ -1,11 +1,11 @@ #include -#define VER_FILEVERSION 1,2,0,0 -#define VER_FILEVERSION_STR "1.2.0.0\0" +#define VER_FILEVERSION 1,3,0,0 +#define VER_FILEVERSION_STR "1.3.0.0\0" #define VER_COMPANYNAME_STR "dSPACE GmbH" #define VER_PRODUCTNAME_STR "V2gCertificateInfos" -#define VER_PRODUCTVERSION 1,2,0,0 -#define VER_PRODUCTVERSION_STR "1.2.0.0\0" +#define VER_PRODUCTVERSION 1,3,0,0 +#define VER_PRODUCTVERSION_STR "1.3.0.0\0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION diff --git a/V2G_Libraries/V2GDecoder/main.rc b/V2G_Libraries/V2GDecoder/main.rc index 0456968..93cfe4d 100644 --- a/V2G_Libraries/V2GDecoder/main.rc +++ b/V2G_Libraries/V2GDecoder/main.rc @@ -1,11 +1,11 @@ #include -#define VER_FILEVERSION 1,2,0,0 -#define VER_FILEVERSION_STR "1.2.0.0\0" +#define VER_FILEVERSION 1,3,0,0 +#define VER_FILEVERSION_STR "1.3.0.0\0" #define VER_COMPANYNAME_STR "dSPACE GmbH" #define VER_PRODUCTNAME_STR "V2gDecoder" -#define VER_PRODUCTVERSION 1,2,0,0 -#define VER_PRODUCTVERSION_STR "1.2.0.0\0" +#define VER_PRODUCTVERSION 1,3,0,0 +#define VER_PRODUCTVERSION_STR "1.3.0.0\0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION diff --git a/Wireshark/plugins/v2gmsg.lua b/Wireshark/plugins/v2gmsg.lua index 79a3628..f7649c7 100644 --- a/Wireshark/plugins/v2gmsg.lua +++ b/Wireshark/plugins/v2gmsg.lua @@ -10,9 +10,9 @@ -- -- See license file (dsV2Gshark_LICENSE.txt) -- -DS_V2GSHARK_VERSION = "1.2.0" -- DO NOT CHANGE +DS_V2GSHARK_VERSION = "1.3.0" -- DO NOT CHANGE -p_v2gmsg = Proto("v2gmsg","V2G Message") +p_v2gmsg = Proto("v2gmsg", "V2G Message") local p_v2gmsg_info = { version = DS_V2GSHARK_VERSION, author = "dSPACE GmbH", @@ -21,16 +21,28 @@ local p_v2gmsg_info = { set_plugin_info(p_v2gmsg_info) -- Load C-Decoder -local v2g_decoder = require('v2gLuaDecoder') +local v2g_decoder = require("v2gLuaDecoder") v2g_decoder.initValidator() -local cert_info_extractor = require('v2gX509CertInfos') +local cert_info_extractor = require("v2gX509CertInfos") -- Settings p_v2gmsg.prefs["infotext"] = Pref.statictext("dSPACE V2Gshark Wireshark Plugin") p_v2gmsg.prefs["additionalinfo"] = Pref.statictext("powered by chargebyte cbExiGen") p_v2gmsg.prefs["additionalinfo2"] = Pref.statictext("") -p_v2gmsg.prefs["portrange_tlssecret"] = Pref.range("TLS secret UDP port(s)", "49152-65535", "UDP source ports of TLS secret disclosure packets.\n\nDefault: '49152-65535'", 65535) -p_v2gmsg.prefs["portrange_v2g"] = Pref.range("V2G message TCP port(s)", "49152-65535", "TCP source ports of V2G request and response messages.\n\nDefault: '49152-65535'", 65535) +p_v2gmsg.prefs["portrange_tlssecret"] = + Pref.range( + "TLS secret UDP port(s)", + "49152-65535", + "UDP source ports of TLS secret disclosure packets.\n\nDefault: '49152-65535'", + 65535 +) +p_v2gmsg.prefs["portrange_v2g"] = + Pref.range( + "V2G message TCP port(s)", + "49152-65535", + "TCP source ports of V2G request and response messages.\n\nDefault: '49152-65535'", + 65535 +) p_v2gmsg.prefs["additionalinfo3"] = Pref.statictext("") p_v2gmsg.prefs["versioninfo"] = Pref.statictext("Version " .. DS_V2GSHARK_VERSION) @@ -48,7 +60,7 @@ selected_schema_at_packet_nr = {} -- maps packet number of SAP res to ProtocolNa -- Wireshark: ProtoFields init local f_entry = ProtoField.string("v2gmsg.entry", " ") -local f_schema = ProtoField.string("v2gmsg.schema", "Schema",base.ASCII) +local f_schema = ProtoField.string("v2gmsg.schema", "Schema", base.ASCII) local f_exi = ProtoField.string("v2gmsg.exi", "EXI", base.ASCII) local f_xml = ProtoField.string("v2gmsg.xml", "Decoded XML", base.ASCII) local f_msg = ProtoField.string("v2gmsg.msgname", "Message", base.ASCII) @@ -57,12 +69,29 @@ local f_validation = ProtoField.string("v2gmsg.validation", "Message Validation" p_v2gmsg.fields = {f_schema, f_exi, f_msg, f_entry, f_xml, f_validation} local values_to_plot = { - "EVTargetVoltage","EVTargetCurrent","EVSEPresentVoltage","EVSEPresentCurrent", -- common - "EVRESSSOC","EVRESSSOC","EVMaximumVoltageLimit","EVMaximumCurrentLimit","EVSEMaximumVoltageLimit","EVSEMaximumCurrentLimit", -- DIN/ISO2 - "EVPresentVoltage","PresentSOC","EVMaximumVoltage","EVMinimumVoltage","EVMaximumChargeCurrent","EVSEMaximumVoltage","EVSEMaximumChargeCurrent" -- ISO20 + -- common + "EVTargetVoltage", + "EVTargetCurrent", + "EVSEPresentVoltage", + "EVSEPresentCurrent", + -- DIN/ISO2: + "EVRESSSOC", + "EVRESSSOC", + "EVMaximumVoltageLimit", + "EVMaximumCurrentLimit", + "EVSEMaximumVoltageLimit", + "EVSEMaximumCurrentLimit", + -- ISO20 + "EVPresentVoltage", + "PresentSOC", + "EVMaximumVoltage", + "EVMinimumVoltage", + "EVMaximumChargeCurrent", + "EVSEMaximumVoltage", + "EVSEMaximumChargeCurrent" } local f_plot_fields = {} -- maps value name to iograph-field -for k,value in pairs(values_to_plot) do +for k, value in pairs(values_to_plot) do f_plot_fields[value] = ProtoField.double("v2gmsg.xml.iograph." .. value, "I/O Graph Value") table.insert(p_v2gmsg.fields, f_plot_fields[value]) end @@ -70,19 +99,25 @@ end local MAX_FIELD_STR_LEN = 150 local ef_warning_generic = ProtoExpert.new("v2gmsg.warning", "V2G Warning", expert.group.PROTOCOL, expert.severity.WARN) -local ef_warning_validation = ProtoExpert.new("v2gmsg.warning.validation", "V2G-Message validation failed", expert.group.PROTOCOL, expert.severity.WARN) +local ef_warning_validation = + ProtoExpert.new( + "v2gmsg.warning.validation", + "V2G-Message validation failed", + expert.group.PROTOCOL, + expert.severity.WARN +) local ef_error_generic = ProtoExpert.new("v2gmsg.error", "V2G Error", expert.group.UNDECODED, expert.severity.ERROR) p_v2gmsg.experts = {ef_warning_generic, ef_warning_validation, ef_error_generic} local schema_namespace_to_schema_ID = {} -schema_namespace_to_schema_ID["urn:iso:15118:2:2010:AppProtocol"] = "SAP" -schema_namespace_to_schema_ID["urn:din:70121:2012:MsgDef"] = "DIN" -schema_namespace_to_schema_ID["urn:iso:15118:2:2013:MsgDef"] = "ISO-2" +schema_namespace_to_schema_ID["urn:iso:15118:2:2010:AppProtocol"] = "SAP" +schema_namespace_to_schema_ID["urn:din:70121:2012:MsgDef"] = "DIN" +schema_namespace_to_schema_ID["urn:iso:15118:2:2013:MsgDef"] = "ISO-2" schema_namespace_to_schema_ID["urn:iso:std:iso:15118:-20:CommonMessages"] = "ISO-20 CM" -schema_namespace_to_schema_ID["urn:iso:std:iso:15118:-20:DC"] = "ISO-20 DC" -schema_namespace_to_schema_ID["urn:iso:std:iso:15118:-20:AC"] = "ISO-20 AC" -schema_namespace_to_schema_ID["urn:iso:std:iso:15118:-20:ACDP"] = "ISO-20 ACDP" -schema_namespace_to_schema_ID["urn:iso:std:iso:15118:-20:WPT"] = "ISO-20 WPT" +schema_namespace_to_schema_ID["urn:iso:std:iso:15118:-20:DC"] = "ISO-20 DC" +schema_namespace_to_schema_ID["urn:iso:std:iso:15118:-20:AC"] = "ISO-20 AC" +schema_namespace_to_schema_ID["urn:iso:std:iso:15118:-20:ACDP"] = "ISO-20 ACDP" +schema_namespace_to_schema_ID["urn:iso:std:iso:15118:-20:WPT"] = "ISO-20 WPT" -- reset everything on init (e.g., if new pcap is opened on same instance) function p_v2gmsg.init() @@ -115,7 +150,7 @@ local function decode_v2g_message(schema, exi_string, packet_number) errn = errn_auto end end - + decoded_with_schema_namespace[packet_number] = xml_schema decoded_error_code[packet_number] = errn return xml_out @@ -132,7 +167,6 @@ end local function add_xml_table_to_tree(xml_table, tree_out, dissector_field, pinfo) local new_element if xml_table.value ~= "" then - -- special handling for certificates if xml_table.name == "Certificate" or xml_table.name == "OEMProvisioningCert" then local cert_element = tree_out:add(dissector_field, xml_table.value) @@ -142,11 +176,30 @@ local function add_xml_table_to_tree(xml_table, tree_out, dissector_field, pinfo cert_element:set_text(xml_table.name .. ": " .. xml_table.value) end - local valid, subj, issuer, version, serial, not_before, not_after, sig_algo, sig_value, pk_algo, spk_curve, spk_pub, v3_constraint, v3_constraint_CA, v3_key_usage, v3_key_usage_crit, v3_sk_ID, v3_sk_ID_crit = cert_info_extractor.getX509Infos(xml_table.value) + local valid, + subj, + issuer, + version, + serial, + not_before, + not_after, + sig_algo, + sig_value, + pk_algo, + spk_curve, + spk_pub, + v3_constraint, + v3_constraint_CA, + v3_key_usage, + v3_key_usage_crit, + v3_sk_ID, + v3_sk_ID_crit = cert_info_extractor.getX509Infos(xml_table.value) if valid then cert_element:add(dissector_field, subj):set_text("Subject: " .. subj) cert_element:add(dissector_field, issuer):set_text("Issuer: " .. issuer) - cert_element:add(dissector_field, version):set_text("Version: v" .. (version + 1) .. " (" .. version .. ")") -- certificate version is always +1 according to the standard + cert_element:add(dissector_field, version):set_text( + "Version: v" .. (version + 1) .. " (" .. version .. ")" + ) -- certificate version is always +1 according to the standard cert_element:add(dissector_field, serial):set_text("Serial Number: 0x" .. serial) cert_element:add(dissector_field, not_before):set_text("Not Valid Before: " .. not_before) cert_element:add(dissector_field, not_after):set_text("Not Valid After: " .. not_after) @@ -158,7 +211,9 @@ local function add_xml_table_to_tree(xml_table, tree_out, dissector_field, pinfo local x509_v3_element = cert_element:add(dissector_field, "X509v3") x509_v3_element:set_text("X509v3") x509_v3_element:add(dissector_field, v3_constraint):set_text("Basic Constraint: " .. v3_constraint) - x509_v3_element:add(dissector_field, v3_constraint_CA):set_text("Basic Constraint CA: " .. v3_constraint_CA) + x509_v3_element:add(dissector_field, v3_constraint_CA):set_text( + "Basic Constraint CA: " .. v3_constraint_CA + ) x509_v3_element:add(dissector_field, v3_key_usage_crit):set_text("Key Usage: " .. v3_key_usage_crit) x509_v3_element:add(dissector_field, v3_key_usage):set_text("Key Usage: " .. v3_key_usage) x509_v3_element:add(dissector_field, v3_sk_ID_crit):set_text("Subject Key ID: " .. v3_sk_ID_crit) @@ -177,10 +232,10 @@ local function add_xml_table_to_tree(xml_table, tree_out, dissector_field, pinfo -- physical value type (15118-2/DIN) local calc_value = nil - if #xml_table.children == 3 and - xml_table.children[1].name == "Multiplier" and - xml_table.children[2].name == "Unit" and - xml_table.children[3].name == "Value" then + if + #xml_table.children == 3 and xml_table.children[1].name == "Multiplier" and xml_table.children[2].name == "Unit" and + xml_table.children[3].name == "Value" + then -- 15118-2 physical value type calc_value = tonumber(xml_table.children[3].value) * 10 ^ tonumber(xml_table.children[1].value) @@ -191,18 +246,30 @@ local function add_xml_table_to_tree(xml_table, tree_out, dissector_field, pinfo end if unit == "s" then - local h = math.floor(calc_value/3600) - local m = math.floor((calc_value - h * 3600)/ 60) + local h = math.floor(calc_value / 3600) + local m = math.floor((calc_value - h * 3600) / 60) local s = calc_value % 60 local appendix - if pcall(function() appendix = string.format(": %02d:%02d:%02d [hh:mm:ss]", h, m, s) end) == false then + if + pcall( + function() + appendix = string.format(": %02d:%02d:%02d [hh:mm:ss]", h, m, s) + end + ) == false + then appendix = ": ?" add_expert_info("INVALID FORMAT", new_element, pinfo, ef_warning_generic) end new_element:append_text(appendix) else local appendix - if pcall(function() appendix = string.format(": %s%s", tostring(calc_value):gsub(",","."), unit) end) == false then + if + pcall( + function() + appendix = string.format(": %s%s", tostring(calc_value):gsub(",", "."), unit) + end + ) == false + then appendix = ": ?" add_expert_info("INVALID FORMAT", new_element, pinfo, ef_warning_generic) end @@ -211,13 +278,15 @@ local function add_xml_table_to_tree(xml_table, tree_out, dissector_field, pinfo end -- rational number type (15118-20 + DIN without unnit) - if #xml_table.children == 2 and - (xml_table.children[1].name == "Exponent" or xml_table.children[1].name == "Multiplier") and - xml_table.children[2].name == "Value" then + if + #xml_table.children == 2 and + (xml_table.children[1].name == "Exponent" or xml_table.children[1].name == "Multiplier") and + xml_table.children[2].name == "Value" + then calc_value = tonumber(xml_table.children[2].value) * 10 ^ tonumber(xml_table.children[1].value) - new_element:append_text(": " .. tostring(calc_value):gsub(",",".")) + new_element:append_text(": " .. tostring(calc_value):gsub(",", ".")) end - + -- add I/O Graph fields for name, field in pairs(f_plot_fields) do if name == xml_table.name then @@ -247,7 +316,7 @@ local function parse_XML(xml_string) local xml_table = {name = "root", attributes = "", parent = nil, children = {}, value = ""} local current_element = xml_table - for op, tag, attr, unary, val in string.gmatch(xml_string:gsub("\n",""), "<(%/?)([%w_:-]+)(.-)(%/?)>([^<]*)") do + for op, tag, attr, unary, val in string.gmatch(xml_string:gsub("\n", ""), "<(%/?)([%w_:-]+)(.-)(%/?)>([^<]*)") do if op == "/" then -- close the current element current_element = current_element.parent @@ -272,19 +341,19 @@ local function parse_XML(xml_string) end local function process_SAP(data, packet_number) - for sap_type in data:gmatch'<[^:]+:supportedAppProtocol([^ >]+)' do + for sap_type in data:gmatch "<[^:]+:supportedAppProtocol([^ >]+)" do -- the SAP-req contains a list of protocols from which one is selected in the SAP-Res by the concrete ID if sap_type == "Req" then - for protocol_entry in data:gmatch'(.-)' do - local proto_namespace = protocol_entry:match'(.-)' - local proto_ID = protocol_entry:match'(.-)' + for protocol_entry in data:gmatch "(.-)" do + local proto_namespace = protocol_entry:match "(.-)" + local proto_ID = protocol_entry:match "(.-)" if proto_namespace ~= nil and proto_ID ~= nil then last_schema_list_SAP_req[proto_ID] = proto_namespace -- else: the request is invalid end end elseif sap_type == "Res" and selected_schema_at_packet_nr[packet_number] == nil then - local selected_ID = data:match'(.-)' + local selected_ID = data:match "(.-)" if selected_ID ~= nil then selected_schema_at_packet_nr[packet_number] = last_schema_list_SAP_req[selected_ID] last_schema_list_SAP_req = {} @@ -295,7 +364,7 @@ local function process_SAP(data, packet_number) end local function get_message_name(data) - local message_name = data:match'><(.-)[ >]' -- SAP / -20 + local message_name = data:match "><(.-)[ >]" -- SAP / -20 if message_name ~= nil then local prefix_at = message_name:find(":") -- cut prefix @@ -303,7 +372,7 @@ local function get_message_name(data) message_name = message_name:sub(prefix_at + 1) end if message_name == "V2G_Message" then - message_name = data:match'Body><(.-)[/ >]' -- ISO-2/DIN + message_name = data:match "Body><(.-)[/ >]" -- ISO-2/DIN prefix_at = message_name:find(":") -- cut prefix if prefix_at ~= nil then message_name = message_name:sub(prefix_at + 1) @@ -351,7 +420,12 @@ function p_v2gmsg.dissector(buf, pinfo, root) if xml_data == nil then -- decoding failed pinfo.cols.info = "V2GMSG - Decoding failed" - add_expert_info("Decoding failed! Is the schema and payload-type correct?", subtree, pinfo, ef_error_generic) + add_expert_info( + "Decoding failed! Is the schema and payload-type correct?", + subtree, + pinfo, + ef_error_generic + ) return end @@ -379,7 +453,12 @@ function p_v2gmsg.dissector(buf, pinfo, root) end end if validation_buffer[pinfo.number] ~= nil then - add_expert_info("This message is invalid: " .. validation_buffer[pinfo.number]:sub(1,-2), subtree, pinfo, ef_warning_validation) + add_expert_info( + "This message is invalid: " .. validation_buffer[pinfo.number]:sub(1, -2), + subtree, + pinfo, + ef_warning_validation + ) end end end @@ -392,7 +471,12 @@ function p_v2gmsg.dissector(buf, pinfo, root) if xml_data == nil then -- decoding failed pinfo.cols.info = "V2GMSG - Decoding failed" - add_expert_info("Decoding failed! Is the schema and payload-type correct?", subtree, pinfo, ef_error_generic) + add_expert_info( + "Decoding failed! Is the schema and payload-type correct?", + subtree, + pinfo, + ef_error_generic + ) return end @@ -411,20 +495,32 @@ function p_v2gmsg.dissector(buf, pinfo, root) end -- add XML data - ByteArray.tvb(ByteArray.new(xml_data, true), "XML Data"); + ByteArray.tvb(ByteArray.new(xml_data, true), "XML Data") metadata_tree:add(f_xml, xml_data) local decoded_schema = decoded_with_schema_namespace[pinfo.number] if decoded_schema ~= nil then -- check decode error if decoded_error_code[pinfo.number] ~= 0 then - add_expert_info("Decoding failed (" .. decoded_error_code[pinfo.number] .. ")! The decoded message is partially or completely invalid!", subtree, pinfo, ef_error_generic) + add_expert_info( + "Decoding failed (" .. + decoded_error_code[pinfo.number] .. ")! The decoded message is partially or completely invalid!", + subtree, + pinfo, + ef_error_generic + ) end -- add validation error message if available if validation_buffer[pinfo.number] ~= nil then - validation_tree = metadata_tree:add(f_validation, "Failed! " .. validation_buffer[pinfo.number]:sub(1,-2)) - add_expert_info("This message is invalid: " .. validation_buffer[pinfo.number]:sub(1,-2), validation_tree, pinfo, ef_warning_validation) + validation_tree = + metadata_tree:add(f_validation, "Failed! " .. validation_buffer[pinfo.number]:sub(1, -2)) + add_expert_info( + "This message is invalid: " .. validation_buffer[pinfo.number]:sub(1, -2), + validation_tree, + pinfo, + ef_warning_validation + ) else metadata_tree:add(f_validation, "Successful") end @@ -450,7 +546,12 @@ function p_v2gmsg.dissector(buf, pinfo, root) pinfo.cols.protocol = "V2GMSG (Decode Error)" metadata_tree:add(f_schema, "Decode Error") metadata_tree:add(f_validation, "Skipped (Decode Error)") - add_expert_info("Decoding failed! The decoded message is partially or completely invalid!", subtree, pinfo, ef_error_generic) + add_expert_info( + "Decoding failed! The decoded message is partially or completely invalid!", + subtree, + pinfo, + ef_error_generic + ) add_xml_table_to_tree(parse_XML(xml_data), subtree, f_entry, pinfo) end end diff --git a/Wireshark/plugins/v2gsdp.lua b/Wireshark/plugins/v2gsdp.lua index 2406624..be21e82 100644 --- a/Wireshark/plugins/v2gsdp.lua +++ b/Wireshark/plugins/v2gsdp.lua @@ -5,111 +5,109 @@ -- See license file (dsV2Gshark_LICENSE.txt) -- -p_sdpreq = Proto("v2gsdp-req","V2G SECC Discovery Protocol Request") -p_sdpres = Proto("v2gsdp-res","V2G SECC Discovery Protocol Response") +p_sdpreq = Proto("v2gsdp-req", "V2G SECC Discovery Protocol Request") +p_sdpres = Proto("v2gsdp-res", "V2G SECC Discovery Protocol Response") local p_v2gsdp_info = { version = DS_V2GSHARK_VERSION, - author = "dSPACE GmbH", + author = "dSPACE GmbH" } set_plugin_info(p_v2gsdp_info) - -- V2G SDP Request -local f_req_sec = ProtoField.uint8("v2gsdp-req.security","Security",base.HEX) -local f_req_tp = ProtoField.uint8("v2gsdp-req.transportprotocol","Transport Protocol",base.HEX) +local f_req_sec = ProtoField.uint8("v2gsdp-req.security", "Security", base.HEX) +local f_req_tp = ProtoField.uint8("v2gsdp-req.transportprotocol", "Transport Protocol", base.HEX) local f_req_emsp_ids = ProtoField.string("v2gsdp-req.emsp", "EMSP IDs") local WITH_TLS = 0 local NO_TLS = 16 local sec_types = { - [WITH_TLS] = "Secured with TLS", -- 0x00 - [NO_TLS] = "No transport layer security", -- 0x10 + [WITH_TLS] = "Secured with TLS", -- 0x00 + [NO_TLS] = "No transport layer security" -- 0x10 } -p_sdpreq.fields = {f_req_sec,f_req_tp,f_req_emsp_ids} +p_sdpreq.fields = {f_req_sec, f_req_tp, f_req_emsp_ids} -- SDP Request dissection function -function p_sdpreq.dissector(buf,pinfo,root) +function p_sdpreq.dissector(buf, pinfo, root) pinfo.cols.protocol = "V2GMSG (SDP)" -- create subtree - subtree = root:add(p_sdpreq,buf(0)) + subtree = root:add(p_sdpreq, buf(0)) -- add protocol fields to subtree local emsp = pinfo.private["SDP_ESMP"] if emsp ~= nil and emsp == true then + -- else: emsp list is empty -- Note: the SDP_RES_EMSP misses the fields 'Security' and 'Transport Protocol', -- since EMPS is only useful with PnC (TCP + TLS) if buf:len() > 0 then - subtree:add(f_req_emsp_ids, buf(0)) + subtree:add(f_req_emsp_ids, buf(0)) end - -- else: emsp list is empty else -- Security - local sec_num = buf(0,1):uint() - local sec = subtree:add(f_req_sec,buf(0,1)) + local sec_num = buf(0, 1):uint() + local sec = subtree:add(f_req_sec, buf(0, 1)) if sec_types[sec_num] ~= nil then - sec:append_text(" (" .. sec_types[sec_num] ..")") + sec:append_text(" (" .. sec_types[sec_num] .. ")") -- Concatenate the info of v2g pinfo.cols.info = tostring(pinfo.cols.info) .. ", " .. sec_types[sec_num] end -- Transport Protocol - local tp = subtree:add(f_req_tp,buf(1,1)) - if buf(1,1):uint() == 0 then + local tp = subtree:add(f_req_tp, buf(1, 1)) + if buf(1, 1):uint() == 0 then tp:append_text(" (TCP)") end end end -- V2G SDP Response -local f_res_ipv6 = ProtoField.ipv6("v2gsdp-res.ipv6","SECC IP Address") -local f_res_port = ProtoField.uint16("v2gsdp-res.port","SECC Port") -local f_res_sec = ProtoField.uint8("v2gsdp-res.security","Security",base.HEX) -local f_res_tp = ProtoField.uint8("v2gsdp-res.transportprotocol","Transport Protocol",base.HEX) +local f_res_ipv6 = ProtoField.ipv6("v2gsdp-res.ipv6", "SECC IP Address") +local f_res_port = ProtoField.uint16("v2gsdp-res.port", "SECC Port") +local f_res_sec = ProtoField.uint8("v2gsdp-res.security", "Security", base.HEX) +local f_res_tp = ProtoField.uint8("v2gsdp-res.transportprotocol", "Transport Protocol", base.HEX) local f_res_emsp_ids = ProtoField.string("v2gsdp-res.emsp", "EMSP IDs") -p_sdpres.fields = {f_res_ipv6,f_res_port,f_res_sec,f_res_tp,f_res_emsp_ids} +p_sdpres.fields = {f_res_ipv6, f_res_port, f_res_sec, f_res_tp, f_res_emsp_ids} -- SDP Response dissection function -function p_sdpres.dissector(buf,pinfo,root) +function p_sdpres.dissector(buf, pinfo, root) pinfo.cols.protocol = "V2GMSG (SDP)" -- create subtree - local subtree = root:add(p_sdpres,buf(0)) + local subtree = root:add(p_sdpres, buf(0)) -- add protocol fields to subtree -- SECC IPv6 - subtree:add(f_res_ipv6,buf(0,16)) + subtree:add(f_res_ipv6, buf(0, 16)) -- SECC Port - subtree:add(f_res_port,buf(16,2)) - + subtree:add(f_res_port, buf(16, 2)) local emsp = pinfo.private["SDP_ESMP"] if emsp ~= nil and emsp == true and buf:len() > 18 then -- Note: the SDP_RES_EMSP misses the fields 'Security' and 'Transport Protocol', -- since EMPS is only useful with PnC (TCP + TLS) - subtree:add(f_req_emsp_ids, buf(18)) + subtree:add(f_req_emsp_ids, buf(18)) else -- Security - local sec_num = buf(18,1):uint() - local sec = subtree:add(f_res_sec,buf(18,1)) + local sec_num = buf(18, 1):uint() + local sec = subtree:add(f_res_sec, buf(18, 1)) if sec_types[sec_num] ~= nil then - sec:append_text(" (" .. sec_types[sec_num] ..")") + sec:append_text(" (" .. sec_types[sec_num] .. ")") -- Concatenate the info of v2g pinfo.cols.info = tostring(pinfo.cols.info) .. ", " .. sec_types[sec_num] end -- Transport Protocol - local tp = subtree:add(f_res_tp,buf(19,1)) - if buf(19,1):uint() == 0 then + local tp = subtree:add(f_res_tp, buf(19, 1)) + if buf(19, 1):uint() == 0 then tp:append_text(" (TCP)") if sec_num == NO_TLS then - DissectorTable.get("tcp.port"):add(buf(16,2):uint(),Dissector.get("v2gtp")) + DissectorTable.get("tcp.port"):add(buf(16, 2):uint(), Dissector.get("v2gtp")) elseif sec_num == WITH_TLS then - DissectorTable.get("tls.port"):add(buf(16,2):uint(),Dissector.get("v2gtp")) + DissectorTable.get("tls.port"):add(buf(16, 2):uint(), Dissector.get("v2gtp")) end end end diff --git a/Wireshark/plugins/v2gtlssecret.lua b/Wireshark/plugins/v2gtlssecret.lua index 14c6e0d..22beee7 100644 --- a/Wireshark/plugins/v2gtlssecret.lua +++ b/Wireshark/plugins/v2gtlssecret.lua @@ -6,7 +6,7 @@ -- See license file (dsV2Gshark_LICENSE.txt) -- -p_v2gtlssecret = Proto("v2gtlssecret","V2G TLS secret") +p_v2gtlssecret = Proto("v2gtlssecret", "V2G TLS secret") local p_v2gtlssecret_info = { version = DS_V2GSHARK_VERSION, author = "dSPACE GmbH" @@ -15,10 +15,18 @@ set_plugin_info(p_v2gtlssecret_info) local min_wireshark_version = "3.5.0" -local f_cr = ProtoField.string("v2gtlssecret.clientrandom","NSS Key Log",base.ASCII) +local f_cr = ProtoField.string("v2gtlssecret.clientrandom", "NSS Key Log", base.ASCII) -local ef_io_error = ProtoExpert.new("tls_secret", "Failed to open keylog-file!", expert.group.DECRYPTION, expert.severity.WARN) -local ef_bad_version = ProtoExpert.new("tls_secret", "To use the TLS disclosure message to decrypt the application data Wireshark/Tshark version " .. tostring(min_wireshark_version) .. " or higher is required.", expert.group.DECRYPTION, expert.severity.WARN) +local ef_io_error = + ProtoExpert.new("tls_secret", "Failed to open keylog-file!", expert.group.DECRYPTION, expert.severity.WARN) +local ef_bad_version = + ProtoExpert.new( + "tls_secret", + "To use the TLS disclosure message to decrypt the application data Wireshark/Tshark version " .. + tostring(min_wireshark_version) .. " or higher is required.", + expert.group.DECRYPTION, + expert.severity.WARN +) local tmpDir = os.getenv("TEMP") if tmpDir == nil then @@ -31,36 +39,51 @@ local frame_numbers = {} -- save the numbers of the frames including TLS secrets p_v2gtlssecret.fields = {f_cr} p_v2gtlssecret.experts = {ef_io_error, ef_bad_version} - -- verify tshark/wireshark version is compatible local function check_version(required_version) major_req, minor_req, micro_req = required_version:match("(%d+)%.(%d+)%.(%d+)") major, minor, micro = get_version():match("(%d+)%.(%d+)%.(%d+)") - if (tonumber(major) < tonumber(major_req)) or - ((tonumber(major) == tonumber(major_req)) and (tonumber(minor) < tonumber(minor_req))) or - ((tonumber(major) == tonumber(major_req)) and (tonumber(minor) == tonumber(minor_req)) and (tonumber(micro) < tonumber(micro_req))) then + if + (tonumber(major) < tonumber(major_req)) or + ((tonumber(major) == tonumber(major_req)) and (tonumber(minor) < tonumber(minor_req))) or + ((tonumber(major) == tonumber(major_req)) and (tonumber(minor) == tonumber(minor_req)) and + (tonumber(micro) < tonumber(micro_req))) + then return false else return true end end +local function split_string(str) + local parts = {} + for part in str:gmatch "[^ \r\n]+" do + table.insert(parts, part) + end + return parts +end + +local function add_expert_info(message, tree, pinfo, expertinfo) + local oldInfo = tostring(pinfo.cols.info) + if string.len(oldInfo) < 9 or oldInfo:sub(0, 9) ~= "[WARNING]" then + tree:add_proto_expert_info(expertinfo, message) + pinfo.cols.info = "[WARNING] " .. oldInfo + end +end + -- PDU dissection function -function p_v2gtlssecret.dissector(buf,pinfo,root) +function p_v2gtlssecret.dissector(buf, pinfo, root) local str = buf:raw() local tls_secret_list = {} local info_strings = {} - local subtree = root:add(p_v2gtlssecret,buf(0)) - -- one UDP packet may contain several lines, check each line - local byte_offset = 0 - for line in str:gmatch'[^\r\n]+' do + for line in str:gmatch "[^\r\n]+" do -- check if this is really a secret - local match = line:match'^([%u_]+)%d* %x+ %x+$' + local match = line:match "^([%u_]+)%d* %x+ %x+$" if match == nil then - goto continue + return 0 elseif match == "CLIENT_RANDOM" then table.insert(info_strings, "master secret") elseif match == "CLIENT_HANDSHAKE_TRAFFIC_SECRET" then @@ -77,16 +100,20 @@ function p_v2gtlssecret.dissector(buf,pinfo,root) -- one last plausibility check if line:len() > 100 and line:len() < 300 then table.insert(tls_secret_list, line) - subtree:add(f_cr,buf(byte_offset, line:len())) end - ::continue:: - byte_offset = byte_offset + line:len() + 1 end if #tls_secret_list == 0 then return 0 end + local byte_offset = 0 + local subtree = root:add(p_v2gtlssecret, buf(byte_offset)) + for _, v in ipairs(tls_secret_list) do + subtree:add(f_cr, buf(byte_offset, v:len())) + byte_offset = byte_offset + v:len() + 1 -- (+1) for line break + end + -- set info column pinfo.cols.info = "TLS disclosure message for " .. table.concat(info_strings, ", ") @@ -104,7 +131,7 @@ function p_v2gtlssecret.dissector(buf,pinfo,root) -- write TLS secret only once and restart dissector once local already_visited = false - for _,v in ipairs(frame_numbers) do + for _, v in ipairs(frame_numbers) do if v == pinfo.number then already_visited = true end @@ -115,18 +142,39 @@ function p_v2gtlssecret.dissector(buf,pinfo,root) -- check if the TLS secrets are already in the file local file, _, _ = io.open(get_preference("tls.keylog_file"), "r") if file ~= nil then - for line in file:lines() do - local tls_secret_of_file = tostring(line) - for idx = #tls_secret_list, 1, -1 do - if tls_secret_list[idx] == tls_secret_of_file then - table.remove(tls_secret_list, idx) + local file_content = file:read("*a") + file:close(file) + + for idx = #tls_secret_list, 1, -1 do + local to_be_removed = false + local splitted_from_packet = split_string(tls_secret_list[idx]) + for line in file_content:gmatch "[^\r\n]+" do + local splitted_from_file = split_string(tostring(line)) + if #splitted_from_packet == 3 and #splitted_from_file == 3 then + if + splitted_from_file[1] == splitted_from_packet[1] and + splitted_from_file[2] == splitted_from_packet[2] + then + if splitted_from_file[3] == splitted_from_packet[3] then + to_be_removed = true + else + add_expert_info( + 'CLIENT RANDOM part of secret is not unique! ("' .. splitted_from_packet[2] .. '")', + subtree, + pinfo, + ef_io_error + ) + end + end end end + if to_be_removed then + table.remove(tls_secret_list, idx) + end if #tls_secret_list == 0 then break end end - file:close(file) end -- write TLS secret only once @@ -134,8 +182,7 @@ function p_v2gtlssecret.dissector(buf,pinfo,root) local err_str file, err_str, _ = io.open(get_preference("tls.keylog_file"), "a") if file == nil then - subtree:add_proto_expert_info(ef_io_error, err_str) - pinfo.cols.info = "[ERROR] " .. tostring(pinfo.cols.info) + add_expert_info(err_str, subtree, pinfo, ef_io_error) else for _, tls_secret in ipairs(tls_secret_list) do file:write(tls_secret .. "\n") @@ -158,4 +205,5 @@ end -- end function 'p_v2gtlssecret.dissector' function p_v2gtlssecret.init() -- register tls secret ports DissectorTable.get("udp.port"):add(p_v2gmsg.prefs["portrange_tlssecret"], p_v2gtlssecret) + frame_numbers = {} end diff --git a/Wireshark/plugins/v2gtp.lua b/Wireshark/plugins/v2gtp.lua index f61c50c..c13d6d9 100644 --- a/Wireshark/plugins/v2gtp.lua +++ b/Wireshark/plugins/v2gtp.lua @@ -5,68 +5,67 @@ -- See license file (dsV2Gshark_LICENSE.txt) -- -p_v2gtp = Proto("v2gtp","V2G Transfer Protocol") +p_v2gtp = Proto("v2gtp", "V2G Transfer Protocol") local p_v2gtp_info = { version = DS_V2GSHARK_VERSION, - author = "dSPACE GmbH", + author = "dSPACE GmbH" } set_plugin_info(p_v2gtp_info) local V2GTP_HDR_LENGTH = 8 -local f_pv = ProtoField.uint8("v2gtp.protoversion","Protocol Version",base.HEX) -local f_ipv = ProtoField.uint8("v2gtp.inverseprotoversion","Inverse Protocol Version",base.HEX) -local f_pt = ProtoField.uint16("v2gtp.payloadtype","Payload Type",base.HEX) -local f_len = ProtoField.uint32("v2gtp.length","Payload Length",base.DEC) +local f_pv = ProtoField.uint8("v2gtp.protoversion", "Protocol Version", base.HEX) +local f_ipv = ProtoField.uint8("v2gtp.inverseprotoversion", "Inverse Protocol Version", base.HEX) +local f_pt = ProtoField.uint16("v2gtp.payloadtype", "Payload Type", base.HEX) +local f_len = ProtoField.uint32("v2gtp.length", "Payload Length", base.DEC) -local V2G = 32769 +local V2G = 32769 local I20_MAIN = 32770 -local I20_AC = 32771 -local I20_DC = 32772 +local I20_AC = 32771 +local I20_DC = 32772 local I20_ACDP = 32773 -local I20_WPT = 32774 +local I20_WPT = 32774 -- 32775 - 33024 reserved -local I20_SCHEDULE_RENEG = 33025 -- Note: not tested yet. ISO-20 support is expirimental in this version! -local I20_METER_CONF = 33026 -- Note: not tested yet. ISO-20 support is expirimental in this version! +local I20_SCHEDULE_RENEG = 33025 -- Note: not tested yet. ISO-20 support is expirimental in this version! +local I20_METER_CONF = 33026 -- Note: not tested yet. ISO-20 support is expirimental in this version! local I20_ACDP_SYS_STATUS = 33027 -- Note: not tested yet. ISO-20 support is expirimental in this version! -local I20_PARKING_STATUS = 33028 -- Note: not tested yet. ISO-20 support is expirimental in this version! +local I20_PARKING_STATUS = 33028 -- Note: not tested yet. ISO-20 support is expirimental in this version! -- 33029 - 36863 reserved -local SDP_REQ = 36864 -local SDP_RES = 36865 -local SDP_REQ_W = 36866 -local SDP_RES_W = 36867 -local SDP_REQ_EMSP = 36868 -local SDP_RES_EMSP = 36869 +local SDP_REQ = 36864 +local SDP_RES = 36865 +local SDP_REQ_W = 36866 +local SDP_RES_W = 36867 +local SDP_REQ_EMSP = 36868 +local SDP_RES_EMSP = 36869 local payload_types = { - [V2G] = "ISO 15118-2/DIN/SAP", -- 0x8001 - [I20_MAIN] = "ISO 15118-20 Main Stream", - [I20_AC] = "ISO 15118-20 Main AC", - [I20_DC] = "ISO 15118-20 Main DC", - [I20_ACDP] = "ISO 15118-20 ACDP", - [I20_WPT] = "ISO 15118-20 WPT", - [I20_SCHEDULE_RENEG] = "ISO 15118-20 Schedule Renegotiation", -- 0x8101 - [I20_METER_CONF] = "ISO 15118-20 Metering Confirmation", - [I20_ACDP_SYS_STATUS] = "ISO 15118-20 ACDP System Status", - [I20_PARKING_STATUS] = "ISO 15118-20 Parking Status", - [SDP_REQ] = "SDP request message", -- 0x9000 - [SDP_RES] = "SDP response message", -- 0x9001 - [SDP_REQ_W] = "SDP request message Wireless (Not supported yet)", - [SDP_RES_W] = "SDP response message Wireless (Not supported yet)", - [SDP_REQ_EMSP] = "SDP EMSP request message", - [SDP_RES_EMSP] = "SDP EMSP response message", + [V2G] = "ISO 15118-2/DIN/SAP", -- 0x8001 + [I20_MAIN] = "ISO 15118-20 Main Stream", + [I20_AC] = "ISO 15118-20 Main AC", + [I20_DC] = "ISO 15118-20 Main DC", + [I20_ACDP] = "ISO 15118-20 ACDP", + [I20_WPT] = "ISO 15118-20 WPT", + [I20_SCHEDULE_RENEG] = "ISO 15118-20 Schedule Renegotiation", -- 0x8101 + [I20_METER_CONF] = "ISO 15118-20 Metering Confirmation", + [I20_ACDP_SYS_STATUS] = "ISO 15118-20 ACDP System Status", + [I20_PARKING_STATUS] = "ISO 15118-20 Parking Status", + [SDP_REQ] = "SDP request message", -- 0x9000 + [SDP_RES] = "SDP response message", -- 0x9001 + [SDP_REQ_W] = "SDP request message Wireless (Not supported yet)", + [SDP_RES_W] = "SDP response message Wireless (Not supported yet)", + [SDP_REQ_EMSP] = "SDP EMSP request message", + [SDP_RES_EMSP] = "SDP EMSP response message" } - -p_v2gtp.fields = {f_pv,f_ipv,f_pt,f_len} +p_v2gtp.fields = {f_pv, f_ipv, f_pt, f_len} -- PDU dissection function -local function v2gtp_pdu_dissect(buf,pinfo,root) - if tostring(buf(0,2)) ~= "01fe" then +local function v2gtp_pdu_dissect(buf, pinfo, root) + if tostring(buf(0, 2)) ~= "01fe" then return 0 end - local p_type_num = buf(2,2):uint() + local p_type_num = buf(2, 2):uint() local prev_proto = tostring(pinfo.cols.protocol) pinfo.cols.protocol = "V2G TP" @@ -78,19 +77,19 @@ local function v2gtp_pdu_dissect(buf,pinfo,root) -- create subtree -- - local subtree = root:add(p_v2gtp,buf(0)) + local subtree = root:add(p_v2gtp, buf(0)) -- add protocol fields to subtree -- Protocol Version - subtree:add(f_pv,buf(0,1)) + subtree:add(f_pv, buf(0, 1)) -- Inverse Protocol Version - subtree:add(f_ipv,buf(1,1)) + subtree:add(f_ipv, buf(1, 1)) -- Payload type - local p_type = subtree:add(f_pt,buf(2,2)) + local p_type = subtree:add(f_pt, buf(2, 2)) if payload_types[p_type_num] ~= nil then - p_type:append_text(" (" .. payload_types[p_type_num] ..")") + p_type:append_text(" (" .. payload_types[p_type_num] .. ")") -- Concatenate the info of v2g if tostring(pinfo.cols.info) ~= "" then pinfo.cols.info = tostring(pinfo.cols.info) .. ", " .. payload_types[p_type_num] @@ -102,7 +101,7 @@ local function v2gtp_pdu_dissect(buf,pinfo,root) end -- Length - subtree:add(f_len, buf(4,4)) + subtree:add(f_len, buf(4, 4)) -- EMSP if p_type_num == SDP_REQ_EMSP or p_type_num == SDP_RES_EMSP then @@ -115,52 +114,52 @@ local function v2gtp_pdu_dissect(buf,pinfo,root) -- if buf:len() > V2GTP_HDR_LENGTH then if p_type_num == SDP_REQ then - Dissector.get("v2gsdp-req"):call(buf(V2GTP_HDR_LENGTH):tvb(),pinfo,root) + Dissector.get("v2gsdp-req"):call(buf(V2GTP_HDR_LENGTH):tvb(), pinfo, root) elseif p_type_num == SDP_RES then - Dissector.get("v2gsdp-res"):call(buf(V2GTP_HDR_LENGTH):tvb(),pinfo,root) + Dissector.get("v2gsdp-res"):call(buf(V2GTP_HDR_LENGTH):tvb(), pinfo, root) elseif p_type_num == V2G then -- do not set schema for 8001 payloads, s.t. it is derived from the SAP - Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(),pinfo,root) + Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(), pinfo, root) elseif p_type_num == I20_MAIN then pinfo.private["Schema"] = "urn:iso:std:iso:15118:-20:CommonMessages" - Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(),pinfo,root) + Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(), pinfo, root) elseif p_type_num == I20_AC then pinfo.private["Schema"] = "urn:iso:std:iso:15118:-20:AC" - Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(),pinfo,root) + Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(), pinfo, root) elseif p_type_num == I20_DC then pinfo.private["Schema"] = "urn:iso:std:iso:15118:-20:DC" - Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(),pinfo,root) + Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(), pinfo, root) elseif p_type_num == I20_ACDP then pinfo.private["Schema"] = "urn:iso:std:iso:15118:-20:ACDP" - Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(),pinfo,root) + Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(), pinfo, root) elseif p_type_num == I20_WPT then pinfo.private["Schema"] = "urn:iso:std:iso:15118:-20:WPT" - Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(),pinfo,root) + Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(), pinfo, root) elseif p_type_num == I20_SCHEDULE_RENEG then -- the schema must be derived from the SAP in this case. TODO: test this as soon as sidestreams are used - Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(),pinfo,root) + Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(), pinfo, root) elseif p_type_num == I20_METER_CONF then pinfo.private["Schema"] = "urn:iso:std:iso:15118:-20:CommonMessages" -- Meter Conf Sidestream uses common messages only - Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(),pinfo,root) + Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(), pinfo, root) elseif p_type_num == I20_ACDP_SYS_STATUS then pinfo.private["Schema"] = "urn:iso:std:iso:15118:-20:ACDP" - Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(),pinfo,root) + Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(), pinfo, root) elseif p_type_num == I20_PARKING_STATUS then pinfo.private["Schema"] = "urn:iso:std:iso:15118:-20:CommonMessages" - Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(),pinfo,root) + Dissector.get("v2gmsg"):call(buf(V2GTP_HDR_LENGTH):tvb(), pinfo, root) end end end -- main dissection function -function p_v2gtp.dissector(buf,pinfo,root) - return v2gtp_pdu_dissect(buf,pinfo,root) +function p_v2gtp.dissector(buf, pinfo, root) + return v2gtp_pdu_dissect(buf, pinfo, root) end -- initialization routine function p_v2gtp.init() -- register protocol - DissectorTable.get("udp.port"):add(15118,p_v2gtp) - DissectorTable.get("tcp.port"):add(15118,p_v2gtp) - DissectorTable.get("tls.port"):add(15118,p_v2gtp) + DissectorTable.get("udp.port"):add(15118, p_v2gtp) + DissectorTable.get("tcp.port"):add(15118, p_v2gtp) + DissectorTable.get("tls.port"):add(15118, p_v2gtp) end