Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-saphdb.c
blobcbf2aecf6b98e112ff440806bbc6626f4f489aee
1 /* packet-saphdb.c
2 * Routines for SAP HDB (HANA SQL Command Network Protocol) dissection
3 * Copyright 2022, Martin Gallo <martin.gallo [AT] gmail.com>
4 * Code contributed by SecureAuth Corp.
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
14 * This is a dissector that partially implements the HDB protocol. Reference of the protocol can be found in SAP's official documentation:
15 * https://help.sap.com/viewer/7e4aba181371442d9e4395e7ff71b777/2.0.03/en-US/d5b80175490741adbf1a1ba5ec8f2695.html
17 * and the blog series SecureAuth published around the topic "Exploring the SAP HANA SQL Command Network Protocol":
18 * - Protocol Basics and Authentication: https://www.secureauth.com/blog/exploring-sap-hana-sql-command-network-protocol-protocol-basics-and-authentication/
19 * - Password-based Authentication and TLS: https://www.secureauth.com/blog/exploring-sap-hana-sql-command-network-protocol-password-based-authentication-and-tls/
20 * - Federated Authentication: https://www.secureauth.com/blog/exploring-the-sap-hana-sql-command-network-protocol-federated-authentication/
23 #include <config.h>
25 #include <epan/packet.h>
26 #include <epan/prefs.h>
27 #include <epan/expert.h>
28 #include <wsutil/wmem/wmem.h>
29 #include <epan/wmem_scopes.h>
31 #include "packet-tcp.h"
32 #include "packet-tls.h"
36 * Define default ports. The right range should be 3NN13 and 3NN15, but as port numbers are proprietary and not
37 * IANA assigned, we leave only the ones corresponding to the instance 00.
39 #define SAPHDB_PORT_RANGE "30013,30015"
41 /* Header Length */
42 #define SAPHDB_HEADER_LEN 32
44 /* SAP HDB Packet Options values */
45 static const value_string saphdb_message_header_packetoptions_vals[] = {
46 { 0, "Uncompressed" },
47 { 2, "Compressed" },
48 /* NULL */
49 { 0x00, NULL }
52 /* SAP HDB Segment Kind values */
53 static const value_string saphdb_segment_segmentkind_vals[] = {
54 { 0, "Invalid" },
55 { 1, "Request" },
56 { 2, "Reply" },
57 { 5, "Error" },
58 /* NULL */
59 { 0x00, NULL }
62 /* SAP HDB Segment Message Type values */
63 static const value_string saphdb_segment_messagetype_vals[] = {
64 { 0, "NIL" },
65 { 2, "EXECUTEDIRECT" },
66 { 3, "PREPARE" },
67 { 4, "ABAPSTREAM" },
68 { 5, "XA_START" },
69 { 6, "XA_JOIN" },
70 { 7, "XA_COMMIT" },
71 { 13, "EXECUTE" },
72 { 16, "READLOB" },
73 { 17, "WRITELOB" },
74 { 18, "FINDLOB" },
75 { 25, "PING" },
76 { 65, "AUTHENTICATE" },
77 { 66, "CONNECT" },
78 { 67, "COMMIT" },
79 { 68, "ROLLBACK" },
80 { 69, "CLOSERESULTSET" },
81 { 70, "DROPSTATEMENTID" },
82 { 71, "FETCHNEXT" },
83 { 72, "FETCHABSOLUTE" },
84 { 73, "FETCHRELATIVE" },
85 { 74, "FETCHFIRST" },
86 { 75, "FETCHLAST" },
87 { 77, "DISCONNECT" },
88 { 78, "EXECUTEITAB" },
89 { 79, "FETCHNEXTITAB" },
90 { 80, "INSERTNEXTITAB" },
91 { 81, "BATCHPREPARE" },
92 { 82, "DBCONNECTINFO" },
93 { 83, "XOPEN_XASTART" },
94 { 84, "XOPEN_XAEND" },
95 { 85, "XOPEN_XAPREPARE" },
96 { 86, "XOPEN_XACOMMIT" },
97 { 87, "XOPEN_XAROLLBACK" },
98 { 88, "XOPEN_XARECOVER" },
99 { 89, "XOPEN_XAFORGET" },
100 /* NULL */
101 { 0x00, NULL }
104 /* SAP HDB Segment Function Code values */
105 static const value_string saphdb_segment_functioncode_vals[] = {
106 { 0, "NIL" },
107 { 1, "DDL" },
108 { 2, "INSERT" },
109 { 3, "UPDATE" },
110 { 4, "DELETE" },
111 { 5, "SELECT" },
112 { 6, "SELECTFORUPDATE" },
113 { 7, "EXPLAIN" },
114 { 8, "DBPROCEDURECALL" },
115 { 9, "DBPROCEDURECALLWITHRESULT" },
116 { 10, "FETCH" },
117 { 11, "COMMIT" },
118 { 12, "ROLLBACK" },
119 { 13, "SAVEPOINT" },
120 { 14, "CONNECT" },
121 { 15, "WRITELOB" },
122 { 16, "READLOB" },
123 { 17, "PING" },
124 { 18, "DISCONNECT" },
125 { 19, "CLOSECURSOR" },
126 { 20, "FINDLOB" },
127 { 21, "ABAPSTREAM" },
128 { 22, "XASTART" },
129 { 23, "XAJOIN" },
130 { 24, "ITABWRITE" },
131 { 25, "XOPEN_XACONTROL" },
132 { 26, "XOPEN_XAPREPARE" },
133 { 27, "XOPEN_XARECOVER" },
134 /* NULL */
135 { 0x00, NULL }
139 /* SAP HDB Part Kind values */
140 static const value_string saphdb_part_partkind_vals[] = {
141 { 0, "NIL" },
142 { 3, "COMMAND" },
143 { 5, "RESULTSET" },
144 { 6, "ERROR" },
145 { 10, "STATEMENTID" },
146 { 11, "TRANSACTIONID" },
147 { 12, "ROWSAFFECTED" },
148 { 13, "RESULTSETID" },
149 { 15, "TOPOLOGYINFORMATION" },
150 { 16, "TABLELOCATION" },
151 { 17, "READLOBREQUEST" },
152 { 18, "READLOBREPLY" },
153 { 25, "ABAPISTREAM" },
154 { 26, "ABAPOSTREAM" },
155 { 27, "COMMANDINFO" },
156 { 28, "WRITELOBREQUEST" },
157 { 29, "CLIENTCONTEXT" },
158 { 30, "WRITELOBREPLY" },
159 { 32, "PARAMETERS" },
160 { 33, "AUTHENTICATION" },
161 { 34, "SESSIONCONTEXT" },
162 { 35, "CLIENTID" },
163 { 38, "PROFILE" },
164 { 39, "STATEMENTCONTEXT" },
165 { 40, "PARTITIONINFORMATION" },
166 { 41, "OUTPUTPARAMETERS" },
167 { 42, "CONNECTOPTIONS" },
168 { 43, "COMMITOPTIONS" },
169 { 44, "FETCHOPTIONS" },
170 { 45, "FETCHSIZE" },
171 { 47, "PARAMETERMETADATA" },
172 { 48, "RESULTSETMETADATA" },
173 { 49, "FINDLOBREQUEST" },
174 { 50, "FINDLOBREPLY" },
175 { 51, "ITABSHM" },
176 { 53, "ITABCHUNKMETADATA" },
177 { 55, "ITABMETADATA" },
178 { 56, "ITABRESULTCHUNK" },
179 { 57, "CLIENTINFO" },
180 { 58, "STREAMDATA" },
181 { 59, "OSTREAMRESULT" },
182 { 60, "FDAREQUESTMETADATA" },
183 { 61, "FDAREPLYMETADATA" },
184 { 62, "BATCHPREPARE" },
185 { 63, "BATCHEXECUTE" },
186 { 64, "TRANSACTIONFLAGS" },
187 { 65, "ROWSLOTIMAGEPARAMMETADATA" },
188 { 66, "ROWSLOTIMAGERESULTSET" },
189 { 67, "DBCONNECTINFO" },
190 { 68, "LOBFLAGS" },
191 { 69, "RESULTSETOPTIONS" },
192 { 70, "XATRANSACTIONINFO" },
193 { 71, "SESSIONVARIABLE" },
194 { 72, "WORKLOADREPLAYCONTEXT" },
195 { 73, "SQLREPLYOTIONS" },
196 /* NULL */
197 { 0x00, NULL }
201 /* SAP HDB Type values */
202 static const value_string saphdb_part_type_vals[] = {
203 { 0, "NULL" },
204 { 1, "TINYINT" },
205 { 2, "SMALLINT" },
206 { 3, "INT" },
207 { 4, "BIGINT" },
208 { 5, "DECIMAL" },
209 { 6, "REAL" },
210 { 7, "DOUBLE" },
211 { 8, "CHAR" },
212 { 9, "VARCHAR1" },
213 { 10, "NCHAR" },
214 { 11, "NVARCHAR" },
215 { 12, "BINARY" },
216 { 13, "VARBINARY" },
217 { 14, "DATE" },
218 { 15, "TIME" },
219 { 16, "TIMESTAMP" },
220 { 17, "TIME_TZ" },
221 { 18, "TIME_LTZ" },
222 { 19, "TIMESTAMP_TZ" },
223 { 20, "TIMESTAMP_LTZ" },
224 { 21, "INTERVAL_YM" },
225 { 22, "INTERVAL_DS" },
226 { 23, "ROWID" },
227 { 24, "UROWID" },
228 { 25, "CLOB" },
229 { 26, "NCLOB" },
230 { 27, "BLOB" },
231 { 28, "BOOLEAN" },
232 { 29, "STRING" },
233 { 30, "NSTRING" },
234 { 31, "LOCATOR" },
235 { 32, "NLOCATOR" },
236 { 33, "BSTRING" },
237 { 34, "DECIMAL_DIGIT_ARRAY" },
238 { 35, "VARCHAR2" },
239 { 36, "VARCHAR3" },
240 { 37, "NVARCHAR3" },
241 { 38, "VARBINARY3" },
242 { 39, "VARGROUP" },
243 { 40, "TINYINT_NOTNULL" },
244 { 41, "SMALLINT_NOTNULL" },
245 { 42, "INT_NOTNULL" },
246 { 43, "BIGINT_NOTNULL" },
247 { 44, "ARGUMENT" },
248 { 45, "TABLE" },
249 { 46, "CURSOR" },
250 { 47, "SMALLDECIMAL" },
251 { 48, "ABAPSTREAM" },
252 { 49, "ABAPSTRUCT" },
253 { 50, "ARRAY" },
254 { 51, "TEXT" },
255 { 52, "SHORTTEXT" },
256 { 53, "FIXEDSTRING" },
257 { 54, "FIXEDPOINTDECIMAL" },
258 { 55, "ALPHANUM" },
259 { 56, "TLOCATOR" },
260 { 61, "LONGDATE" },
261 { 62, "SECONDDATE" },
262 { 63, "DAYDATE" },
263 { 64, "SECONDTIME" },
264 { 65, "CSDATE" },
265 { 66, "CSTIME" },
266 { 71, "BLOB_DISK" },
267 { 72, "CLOB_DISK" },
268 { 73, "NCLOB_DISK" },
269 { 74, "GEOMETRY" },
270 { 75, "POINT" },
271 { 76, "FIXED16" },
272 { 77, "BLOB_HYBRID" },
273 { 78, "CLOB_HYBRID" },
274 { 79, "NCLOB_HYBRID" },
275 { 80, "POINTZ" },
276 /* NULL */
277 { 0x00, NULL }
280 /* SAP HDB Error Level values */
281 static const value_string saphdb_error_level_vals[] = {
282 { 0, "WARNING" },
283 { 1, "ERROR" },
284 { 2, "FATALERROR" },
285 /* NULL */
286 { 0x00, NULL }
290 /* Structure to define Option Parts */
291 typedef struct _option_part_definition {
292 int8_t value;
293 const char *identifier_strptr;
294 int8_t type;
295 } option_part_definition;
298 static const option_part_definition saphdb_part_connect_options_vals[] = {
299 { 1, "Connection ID", 3 },
300 { 2, "Complete Array Execution", 28 },
301 { 3, "Client Locale", 29 },
302 { 4, "Supports Large Bulk Operations", 28 },
303 { 5, "Distribution Enabled", 28 },
304 { 6, "Primary Connection ID", 0 },
305 { 7, "Primary Connection Host", 0 },
306 { 8, "Primary Connection Port", 0 },
307 { 9, "Complete Data Type Support", 0 },
308 { 10, "Large Number of Parameters Support", 28 },
309 { 11, "System ID", 29 },
310 { 12, "Data Format Version", 3 },
311 { 13, "ABAP VARCHAR Mode", 28 },
312 { 14, "Select for Update Supported", 28 },
313 { 15, "Client Distribution Mode", 3 },
314 { 16, "Engine Data Format Version", 3 },
315 { 17, "Distribution Protocol Version", 3 },
316 { 18, "Split Batch Commands", 28 },
317 { 19, "Use Transaction Flags Only", 28 },
318 { 20, "Row and Column Optimized Format", 28 },
319 { 21, "Ignore Unknown Parts", 3 },
320 { 22, "Table Output Parameter", 28 },
321 { 23, "Data Format Version 2", 3 },
322 { 24, "ITAB Parameter", 28 },
323 { 25, "Describe Table Output Parameter", 28 },
324 { 26, "Columnar Result Set", 0 }, /* This is BITVECTOR type ??? */
325 { 27, "Scrollable Result Set", 3 },
326 { 28, "Client Info NULL Value Supported", 28 },
327 { 29, "Associated Connection ID", 3 },
328 { 30, "Non-Transactional Prepare", 28 },
329 { 31, "Fast Data Access Enabled", 28 },
330 { 32, "OS User", 29 },
331 { 33, "Row Slot Image Result", 0 }, /* This is BITVECTOR type ??? */
332 { 34, "Endianness", 3 },
333 { 35, "Update Topology Anywhere", 28 },
334 { 36, "Enable Array Type", 28 },
335 { 37, "Implicit LOB Streaming", 28 },
336 { 38, "Cached View Property", 28 },
337 { 39, "X OpenXA Protocol Supported", 28 },
338 { 40, "Master Commit Redirection Supported", 28 },
339 { 41, "Active/Active Protocol Version", 3 },
340 { 42, "Active/Active Connection Origin Site", 3 },
341 { 43, "Query Timeout Supported", 28 },
342 { 44, "Full Version String", 29 },
343 { 45, "Database Name", 29 },
344 { 46, "Build Platform", 3 },
345 { 47, "Implicit XA Session Supported", 28 },
346 { 48, "Client Side Column Encryption Version", 3 },
347 { 49, "Compression Level And Flags", 3 },
348 { 50, "Client Side Re-Execution Supported", 28 },
349 { 51, "Client Reconnect Wait Timeout", 3 },
350 { 52, "Original Anchor Connection ID", 3 },
351 { 53, "Flag Set 1", 3 },
352 { 54, "Topology Network Group", 28 },
353 { 55, "IP Address", 29 },
354 { 56, "LRR Ping Time", 3 },
355 /* NULL */
356 { 0x00, NULL, 0x00 }
359 static const option_part_definition saphdb_part_commit_options_vals[] = {
360 { 1, "Hold Cursors Over Commit", 28 },
361 /* NULL */
362 { 0x00, NULL, 0x00 }
365 static const option_part_definition saphdb_part_fetch_options_vals[] = {
366 { 1, "Result Set Pos", 3 },
367 /* NULL */
368 { 0x00, NULL, 0x00 }
371 static const option_part_definition saphdb_part_transaction_flags_vals[] = {
372 { 0, "Rolled Back", 28 },
373 { 1, "Committed", 28 },
374 { 2, "New Isolation Level", 3 },
375 { 3, "DDL Commit Mode Changed", 28 },
376 { 4, "Write Transaction Started", 28 },
377 { 5, "No Write Transaction Started", 28 },
378 { 6, "Session Closing Transaction Error", 28 },
379 /* NULL */
380 { 0x00, NULL, 0x00}
383 static const option_part_definition saphdb_part_topology_info_vals[] = {
384 { 1, "Host Name", 29 },
385 { 2, "Host Port Number", 3 },
386 { 3, "Tenant Name", 29 },
387 { 4, "Load Factor", 7 },
388 { 5, "Site Volume ID", 3 },
389 { 6, "Is Master", 28 },
390 { 7, "Is Current Session", 28 },
391 { 8, "Service Type", 3 },
392 { 9, "Network Domain", 29 },
393 { 10, "Is Stand-By", 28 },
394 { 11, "All IP Addresses", 29 },
395 { 12, "All Host Names", 29 },
396 { 13, "Site Type", 3 },
397 /* NULL */
398 { 0x00, NULL, 0x00 }
401 static const option_part_definition saphdb_part_command_info_vals[] = {
402 { 1, "Line Number", 3 },
403 { 2, "Source Module", 29 },
404 /* NULL */
405 { 0x00, NULL, 0x00 }
408 static const option_part_definition saphdb_part_client_context_vals[] = {
409 { 1, "Client Version", 29 },
410 { 2, "Client Type", 29 },
411 { 3, "Application Name", 29 },
412 /* NULL */
413 { 0x00, NULL, 0x00 }
416 static const option_part_definition saphdb_part_session_context_vals[] = {
417 { 1, "Primary Connection ID", 3 },
418 { 2, "Primary Host Name", 29 },
419 { 3, "Primary Host Port Number", 3 },
420 { 4, "Master Connection ID", 3 },
421 { 5, "Master Host Name", 29 },
422 { 6, "Master Host Port Number", 3 },
423 /* NULL */
424 { 0x00, NULL, 0x00 }
427 static const option_part_definition saphdb_part_statement_context_vals[] = {
428 { 1, "Statement Sequence Info", 33 },
429 { 2, "Server Processing Time", 4 },
430 { 3, "Schema Name", 29 },
431 { 4, "Flag Set", 8 },
432 { 5, "Query Time Out", 4 },
433 { 6, "Client Reconnection Wait Timeout", 3 },
434 { 7, "Server CPU Time", 4 },
435 { 8, "Server Memory Usage", 4 },
436 /* NULL */
437 { 0x00, NULL, 0x00 }
440 static const option_part_definition saphdb_part_dbconnect_info_flags_vals[] = {
441 { 1, "Database Name", 29 },
442 { 2, "Host", 29 },
443 { 3, "Port", 3 },
444 { 4, "Is Connected", 28 },
445 /* NULL */
446 { 0x00, NULL, 0x00 }
449 static const option_part_definition saphdb_part_lob_flags_vals[] = {
450 { 0, "Implicit Streaming", 28 },
451 /* NULL */
452 { 0x00, NULL, 0x00 }
456 static int proto_saphdb;
458 /* SAP HDB Initialization items */
459 static int hf_saphdb_initialization_request;
460 static int hf_saphdb_initialization_reply;
461 static int hf_saphdb_initialization_reply_product_version_major;
462 static int hf_saphdb_initialization_reply_product_version_minor;
463 static int hf_saphdb_initialization_reply_protocol_version_major;
464 static int hf_saphdb_initialization_reply_protocol_version_minor;
466 /* SAP HDB Message Header items */
467 static int hf_saphdb_message_header;
468 static int hf_saphdb_message_header_sessionid;
469 static int hf_saphdb_message_header_packetcount;
470 static int hf_saphdb_message_header_varpartlength;
471 static int hf_saphdb_message_header_varpartsize;
472 static int hf_saphdb_message_header_noofsegm;
473 static int hf_saphdb_message_header_packetoptions;
474 static int hf_saphdb_message_header_compressionvarpartlength;
475 static int hf_saphdb_message_header_reserved;
476 /* SAP HDB Message Buffer items */
477 static int hf_saphdb_message_buffer;
478 static int hf_saphdb_compressed_buffer;
480 /* SAP HDB Segment items */
481 static int hf_saphdb_segment;
482 static int hf_saphdb_segment_segmentlength;
483 static int hf_saphdb_segment_segmentofs;
484 static int hf_saphdb_segment_noofparts;
485 static int hf_saphdb_segment_segmentno;
486 static int hf_saphdb_segment_segmentkind;
487 static int hf_saphdb_segment_messagetype;
488 static int hf_saphdb_segment_commit;
489 static int hf_saphdb_segment_commandoptions;
490 static int hf_saphdb_segment_functioncode;
491 static int hf_saphdb_segment_reserved;
492 /* SAP HDB Segment Buffer items */
493 static int hf_saphdb_segment_buffer;
495 /* SAP HDB Part items */
496 static int hf_saphdb_part;
497 static int hf_saphdb_part_partkind;
498 static int hf_saphdb_part_partattributes;
499 static int hf_saphdb_part_argumentcount;
500 static int hf_saphdb_part_bigargumentcount;
501 static int hf_saphdb_part_bufferlength;
502 static int hf_saphdb_part_buffersize;
503 /* SAP HDB Part Buffer items */
504 static int hf_saphdb_part_buffer;
506 /* SAP HDB Part Buffer Option Part Data items */
507 static int hf_saphdb_part_option_argcount;
508 static int hf_saphdb_part_option_name;
509 static int hf_saphdb_part_option_type;
510 static int hf_saphdb_part_option_length;
511 static int hf_saphdb_part_option_value;
512 static int hf_saphdb_part_option_value_bool;
513 static int hf_saphdb_part_option_value_byte;
514 static int hf_saphdb_part_option_value_short;
515 static int hf_saphdb_part_option_value_int;
516 static int hf_saphdb_part_option_value_bigint;
517 static int hf_saphdb_part_option_value_string;
518 static int hf_saphdb_part_option_value_double;
520 /* SAP HDB Part Buffer COMMAND items */
521 static int hf_saphdb_part_command;
523 /* SAP HDB Part Buffer ERROR items */
524 static int hf_saphdb_part_error_code;
525 static int hf_saphdb_part_error_position;
526 static int hf_saphdb_part_error_text_length;
527 static int hf_saphdb_part_error_level;
528 static int hf_saphdb_part_error_sqlstate;
529 static int hf_saphdb_part_error_text;
531 /* SAP HDB Part Buffer AUTHENTICATE items */
532 static int hf_saphdb_part_authentication_field_count;
533 static int hf_saphdb_part_authentication_field_length;
534 static int hf_saphdb_part_authentication_field_value;
536 /* SAP HDB Part Buffer CLIENTID items */
537 static int hf_saphdb_part_clientid;
540 static int ett_saphdb;
543 /* Global port preference */
544 static range_t *global_saphdb_port_range;
547 /* Expert info */
548 static expert_field ei_saphdb_compressed_unknown;
549 static expert_field ei_saphdb_option_part_unknown;
550 static expert_field ei_saphdb_segments_incorrect_order;
551 static expert_field ei_saphdb_segments_number_incorrect;
552 static expert_field ei_saphdb_segment_length;
553 static expert_field ei_saphdb_buffer_length;
554 static expert_field ei_saphdb_parts_number_incorrect;
555 static expert_field ei_saphdb_varpartlenght_incorrect;
558 /* Global highlight preference */
559 static bool global_saphdb_highlight_items = true;
562 /* Protocol handle */
563 static dissector_handle_t saphdb_handle;
564 static dissector_handle_t saphdb_handle_tls;
565 static dissector_handle_t gssapi_handle;
568 void proto_reg_handoff_saphdb(void);
569 void proto_register_saphdb(void);
572 /* Option Part Value to Option Part Identifier */
573 static const char *
574 opv_to_opi(const int8_t value, const option_part_definition *opd, const char *unknown_str)
576 int i = 0;
577 if (opd) {
578 while (opd[i].identifier_strptr) {
579 if (opd[i].value == value) {
580 return opd[i].identifier_strptr;
582 i++;
585 return unknown_str;
588 /* Option Part Value to Option Part Type */
589 static int8_t
590 opv_to_opt(const int8_t value, const option_part_definition *opd)
592 int i = 0;
593 if (opd) {
594 while (opd[i].identifier_strptr) {
595 if (opd[i].value == value) {
596 return opd[i].type;
598 i++;
601 return 0;
604 static int
605 dissect_saphdb_part_options_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset, int16_t argcount, uint8_t partkind, const option_part_definition *definition)
607 uint32_t parsed_length = 0;
609 while (argcount > 0 && tvb_reported_length_remaining(tvb, offset + parsed_length) > 2) {
610 int8_t option_key = 0, option_type = 0;
611 int16_t option_length = 0;
612 int8_t option_value_byte = 0;
613 proto_item *option_type_item = NULL;
615 option_key = tvb_get_int8(tvb, offset + parsed_length);
616 proto_tree_add_int_format(tree, hf_saphdb_part_option_name, tvb, offset + parsed_length, 1, option_key,
617 "Option Name: %s (%d)", opv_to_opi(option_key, definition, "Unknown"), option_key);
618 parsed_length += 1;
620 option_type = tvb_get_int8(tvb, offset + parsed_length);
621 option_type_item = proto_tree_add_item(tree, hf_saphdb_part_option_type, tvb, offset + parsed_length, 1, ENC_NA);
622 parsed_length += 1;
624 if (option_type != opv_to_opt(option_key, definition)) {
625 if (global_saphdb_highlight_items){
626 expert_add_info_format(pinfo, option_type_item, &ei_saphdb_option_part_unknown, "Option Type for key %d in part kind %d doesn't match! (expected %d, obtained %d)", option_key, partkind, opv_to_opt(option_key, definition), option_type);
630 switch (option_type) {
631 case 1: // TINYINT
632 proto_tree_add_item(tree, hf_saphdb_part_option_value_byte, tvb, offset + parsed_length, 1, ENC_NA);
633 parsed_length += 1;
634 break;
635 case 2: // SMALLINT
636 proto_tree_add_item(tree, hf_saphdb_part_option_value_short, tvb, offset + parsed_length, 2, ENC_LITTLE_ENDIAN);
637 parsed_length += 2;
638 break;
639 case 3: // INT
640 proto_tree_add_item(tree, hf_saphdb_part_option_value_int, tvb, offset + parsed_length, 4, ENC_LITTLE_ENDIAN);
641 parsed_length += 4;
642 break;
643 case 4: // BIGINT
644 proto_tree_add_item(tree, hf_saphdb_part_option_value_bigint, tvb, offset + parsed_length, 8, ENC_LITTLE_ENDIAN);
645 parsed_length += 8;
646 break;
647 case 7: // DOUBLE
648 proto_tree_add_item(tree, hf_saphdb_part_option_value_double, tvb, offset + parsed_length, 8, ENC_LITTLE_ENDIAN);
649 parsed_length += 8;
650 break;
651 case 28: // BOOLEAN
652 option_value_byte = tvb_get_int8(tvb, offset + parsed_length);
653 proto_tree_add_boolean(tree, hf_saphdb_part_option_value_bool, tvb, offset + parsed_length, 1, option_value_byte);
654 parsed_length += 1;
655 break;
656 case 29: // STRING
657 case 30: // NSTRING
658 case 33: // BSTRING
659 option_length = tvb_get_int16(tvb, offset + parsed_length, ENC_LITTLE_ENDIAN);
660 proto_tree_add_item(tree, hf_saphdb_part_option_length, tvb, offset + parsed_length, 2, ENC_LITTLE_ENDIAN);
661 parsed_length += 2;
663 if (tvb_reported_length_remaining(tvb, offset + parsed_length) >= option_length) {
664 if (option_type == 29) {
665 /* TODO: This need to be CESU-8 decoded */
666 proto_tree_add_item(tree, hf_saphdb_part_option_value_string, tvb, offset + parsed_length, option_length, ENC_UTF_8);
667 parsed_length += option_length;
668 } else if (option_type == 30) {
669 proto_tree_add_item(tree, hf_saphdb_part_option_value_string, tvb, offset + parsed_length, option_length, ENC_UTF_8);
670 parsed_length += option_length;
671 } else if (option_type == 33) {
672 /* This is binary data, not rendering it as a string */
673 proto_tree_add_item(tree, hf_saphdb_part_option_value, tvb, offset + parsed_length, option_length, ENC_NA);
674 parsed_length += option_length;
677 break;
678 default: // Unknown type, we don't know the length nor how to parse it
679 if (global_saphdb_highlight_items){
680 expert_add_info_format(pinfo, option_type_item, &ei_saphdb_option_part_unknown, "Option Type %d length unknown", option_type);
682 break;
684 argcount--;
687 return parsed_length;
690 static int
691 dissect_saphdb_part_multi_line_options_data(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset, int16_t rowcount, uint8_t partkind, const option_part_definition *definition)
693 uint32_t parsed_length = 0;
695 /* In Multi-line Option Part, the part's argcount is the number of rows. For each row we need to parse the options. */
696 while (rowcount > 0 && tvb_reported_length_remaining(tvb, offset + parsed_length) > 2) {
697 int16_t argcount = 0;
699 /* First we read the amount of arguments in this row */
700 argcount = tvb_get_int16(tvb, offset + parsed_length, ENC_LITTLE_ENDIAN);
701 proto_tree_add_item(tree, hf_saphdb_part_option_argcount, tvb, offset + parsed_length, 2, ENC_LITTLE_ENDIAN);
702 parsed_length += 2;
704 /* Now parse the options in the row if there are*/
705 if (argcount > 0) {
706 parsed_length += dissect_saphdb_part_options_data(tvb, pinfo, tree, offset + parsed_length, argcount, partkind, definition);
709 rowcount--;
712 return parsed_length;
716 static void
717 dissect_saphdb_gss_authentication_fields(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset)
719 uint8_t field_short_length, commtype = 0;
720 uint16_t field_count = 0, field_length;
722 /* Parse the field count */
723 field_count = tvb_get_uint16(tvb, offset, ENC_LITTLE_ENDIAN);
724 proto_tree_add_item(tree, hf_saphdb_part_authentication_field_count, tvb, offset, 2, ENC_LITTLE_ENDIAN);
725 offset += 2;
727 for (uint16_t field = 0; field < field_count; field++) {
729 /* Parse the field length. If the first byte is 0xFF, the length is contained in the next 2 bytes */
730 field_short_length = tvb_get_uint8(tvb, offset);
731 if (field_short_length == 0xff) {
732 offset += 1;
733 field_length = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
734 proto_tree_add_item(tree, hf_saphdb_part_authentication_field_length, tvb, offset, 2, ENC_BIG_ENDIAN);
735 offset += 2;
736 } else {
737 proto_tree_add_item(tree, hf_saphdb_part_authentication_field_length, tvb, offset, 1, ENC_LITTLE_ENDIAN);
738 offset += 1;
739 field_length = field_short_length;
742 /* We try then to see if we're dealing with the commtype field (second field and with length 1)
743 * and extract it
745 if ((field == 1) && (field_length == 1))
747 commtype = tvb_get_uint8(tvb, offset);
750 /* If this is the last value of a three field packet, and is one of the commtypes that carries an
751 * SPNEGO structure, we call the GSSAPI dissector. The Kerberos data is extracted in a new TVB.
753 if (((commtype == 3) || (commtype == 6)) && (field_count == 3) && (field == 2)) {
754 tvbuff_t *kerberos_tvb;
755 kerberos_tvb = tvb_new_subset_length(tvb, offset, field_length);
756 add_new_data_source(pinfo, kerberos_tvb, "Kerberos Data");
757 call_dissector(gssapi_handle, kerberos_tvb, pinfo, tree);
759 else
760 /* If not we add the field value in plain */
762 proto_tree_add_item(tree, hf_saphdb_part_authentication_field_value, tvb, offset, field_length, ENC_NA);
765 offset += field_length;
771 static int
772 dissect_saphdb_part_authentication_fields(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset)
774 uint8_t field_short_length;
775 uint16_t field_count = 0, field_length;
776 uint32_t parsed_length = 0;
778 proto_item *gss_item = NULL;
779 proto_tree *gss_tree = NULL;
781 bool is_gss = false;
783 /* Parse the field count */ /* TODO: Should this match with argcount? */
784 field_count = tvb_get_uint16(tvb, offset, ENC_LITTLE_ENDIAN);
785 proto_tree_add_item(tree, hf_saphdb_part_authentication_field_count, tvb, offset, 2, ENC_LITTLE_ENDIAN);
786 offset += 2;
787 parsed_length += 2;
789 for (uint16_t field = 0; field < field_count; field++) {
791 /* Parse the field length. If the first byte is 0xFF, the length is contained in the next 2 bytes */
792 field_short_length = tvb_get_uint8(tvb, offset);
793 if (field_short_length == 0xff) {
794 offset += 1;
795 parsed_length += 1;
796 field_length = tvb_get_uint16(tvb, offset, ENC_BIG_ENDIAN);
797 proto_tree_add_item(tree, hf_saphdb_part_authentication_field_length, tvb, offset, 2, ENC_BIG_ENDIAN);
798 offset += 2;
799 parsed_length += 2;
800 } else {
801 proto_tree_add_item(tree, hf_saphdb_part_authentication_field_length, tvb, offset, 1, ENC_LITTLE_ENDIAN);
802 offset += 1;
803 parsed_length += 1;
804 field_length = field_short_length;
807 /* Add the field value */
808 gss_item = proto_tree_add_item(tree, hf_saphdb_part_authentication_field_value, tvb, offset, field_length, ENC_NA);
810 /* Check if this is a GSS field so we can parse the remaining fields */
811 if ((((field_count == 2) && (field == 0)) || ((field_count == 3) && (field == 1))) &&
812 (field_length == 3) && (tvb_strneql(tvb, offset, "GSS", 3) != -1)) {
813 is_gss = true;
816 /* If the method is GSS, and this is the last value, we add a new tree and parse the value */
817 if (is_gss && field == field_count - 1) {
818 proto_item_append_text(gss_item, ": GSS Token");
819 gss_tree = proto_item_add_subtree(gss_item, ett_saphdb);
820 dissect_saphdb_gss_authentication_fields(tvb, pinfo, gss_tree, offset);
823 offset += field_length; parsed_length += field_length;
827 return parsed_length;
831 static int
832 dissect_saphdb_part_buffer(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset, uint32_t length, int16_t argcount, uint8_t partkind, proto_item *partkind_item)
834 int32_t error_text_length = 0;
836 switch (partkind) {
837 case 3: // COMMAND
838 if ((length > 0) && ((uint32_t)tvb_reported_length_remaining(tvb, offset) >= length)) {
839 proto_tree_add_item(tree, hf_saphdb_part_command, tvb, offset, length, ENC_ASCII);
840 length = 0;
842 break;
843 case 6: // ERROR
844 proto_tree_add_item(tree, hf_saphdb_part_error_code, tvb, offset, 4, ENC_LITTLE_ENDIAN);
845 offset += 4;
846 length -= 4;
847 proto_tree_add_item(tree, hf_saphdb_part_error_position, tvb, offset, 4, ENC_LITTLE_ENDIAN);
848 offset += 4;
849 length -= 4;
850 proto_tree_add_item_ret_int(tree, hf_saphdb_part_error_text_length, tvb, offset, 4, ENC_LITTLE_ENDIAN, &error_text_length);
851 offset += 4;
852 length -= 4;
853 proto_tree_add_item(tree, hf_saphdb_part_error_level, tvb, offset, 1, ENC_NA);
854 offset += 1;
855 length -= 1;
856 proto_tree_add_item(tree, hf_saphdb_part_error_sqlstate, tvb, offset, 5, ENC_ASCII);
857 offset += 5;
858 length -= 5;
860 if ((error_text_length > 0) && (tvb_reported_length_remaining(tvb, offset) >= error_text_length)) {
861 proto_tree_add_item(tree, hf_saphdb_part_error_text, tvb, offset, error_text_length, ENC_ASCII);
862 length -= error_text_length;
864 /* Align the error text length to 8 */
865 if ((error_text_length % 8) != 0) {
866 length += 8 - (error_text_length % 8);
869 break;
871 case 33: // AUTHENTICATION
872 dissect_saphdb_part_authentication_fields(tvb, pinfo, tree, offset);
873 break;
875 case 35: // CLIENTID
876 if ((length > 0) && ((uint32_t)tvb_reported_length_remaining(tvb, offset) >= length)) {
877 proto_tree_add_item(tree, hf_saphdb_part_clientid, tvb, offset, length, ENC_ASCII);
878 length = 0;
880 break;
882 // Multi-line Option Parts
883 case 15: // TOPOLOGYINFORMATION
884 dissect_saphdb_part_multi_line_options_data(tvb, pinfo, tree, offset, argcount, partkind, saphdb_part_topology_info_vals);
885 break;
887 // Option Parts
888 case 27: // COMMANDINFO
889 dissect_saphdb_part_options_data(tvb, pinfo, tree, offset, argcount, partkind, saphdb_part_command_info_vals);
890 break;
891 case 29: // CLIENTCONTEXT
892 dissect_saphdb_part_options_data(tvb, pinfo, tree, offset, argcount, partkind, saphdb_part_client_context_vals);
893 break;
894 case 34: // SESSIONCONTEXT
895 dissect_saphdb_part_options_data(tvb, pinfo, tree, offset, argcount, partkind, saphdb_part_session_context_vals);
896 break;
897 case 39: // STATEMENTCONTEXT
898 dissect_saphdb_part_options_data(tvb, pinfo, tree, offset, argcount, partkind, saphdb_part_statement_context_vals);
899 break;
900 case 42: // CONNECTOPTIONS
901 dissect_saphdb_part_options_data(tvb, pinfo, tree, offset, argcount, partkind, saphdb_part_connect_options_vals);
902 break;
903 case 43: // COMMITOPTIONS
904 dissect_saphdb_part_options_data(tvb, pinfo, tree, offset, argcount, partkind, saphdb_part_commit_options_vals);
905 break;
906 case 44: // FETCHOPTIONS
907 dissect_saphdb_part_options_data(tvb, pinfo, tree, offset, argcount, partkind, saphdb_part_fetch_options_vals);
908 break;
909 case 64: // TRANSACTIONFLAGS
910 dissect_saphdb_part_options_data(tvb, pinfo, tree, offset, argcount, partkind, saphdb_part_transaction_flags_vals);
911 break;
912 case 67: // DBCONNECTINFO
913 dissect_saphdb_part_options_data(tvb, pinfo, tree, offset, argcount, partkind, saphdb_part_dbconnect_info_flags_vals);
914 break;
915 case 68: // LOBFLAGS
916 dissect_saphdb_part_options_data(tvb, pinfo, tree, offset, argcount, partkind, saphdb_part_lob_flags_vals);
917 break;
919 default:
920 if (global_saphdb_highlight_items){
921 expert_add_info_format(pinfo, partkind_item, &ei_saphdb_option_part_unknown, "Part Kind %d unknown", partkind);
923 break;
926 return length;
930 static int
931 dissect_saphdb_part(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_, uint32_t offset, int16_t number_of_parts, uint16_t part_number)
933 int8_t partkind = 0;
934 int16_t argcount = 0;
935 int32_t bufferlength = 0;
936 uint32_t length = 0;
937 proto_item *part_item = NULL, *partkind_item = NULL, *part_buffer_length_item = NULL, *part_buffer_item = NULL;
938 proto_tree *part_tree = NULL, *part_buffer_tree = NULL;
940 /* Add the Part subtree */
941 part_item = proto_tree_add_item(tree, hf_saphdb_part, tvb, offset, 16, ENC_NA);
942 part_tree = proto_item_add_subtree(part_item, ett_saphdb);
943 proto_item_append_text(part_item, " (%d/%d)", part_number, number_of_parts);
945 /* Add the Part fields */
946 partkind = tvb_get_int8(tvb, offset);
947 proto_item_append_text(part_item, ", %s", val_to_str_const(partkind, saphdb_part_partkind_vals, "Unknown"));
948 partkind_item = proto_tree_add_item(part_tree, hf_saphdb_part_partkind, tvb, offset, 1, ENC_LITTLE_ENDIAN);
949 offset += 1;
950 length += 1;
951 proto_tree_add_item(part_tree, hf_saphdb_part_partattributes, tvb, offset, 1, ENC_LITTLE_ENDIAN);
952 offset += 1;
953 length += 1;
954 argcount = tvb_get_int16(tvb, offset, ENC_LITTLE_ENDIAN);
955 proto_tree_add_item(part_tree, hf_saphdb_part_argumentcount, tvb, offset, 2, ENC_LITTLE_ENDIAN);
956 offset += 2;
957 length += 2;
958 proto_tree_add_item(part_tree, hf_saphdb_part_bigargumentcount, tvb, offset, 4, ENC_LITTLE_ENDIAN);
959 offset += 4;
960 length += 4;
961 part_buffer_length_item = proto_tree_add_item_ret_int(part_tree, hf_saphdb_part_bufferlength, tvb, offset, 4, ENC_LITTLE_ENDIAN, &bufferlength);
962 offset += 4;
963 length += 4;
964 proto_tree_add_item(part_tree, hf_saphdb_part_buffersize, tvb, offset, 4, ENC_LITTLE_ENDIAN);
965 offset += 4;
966 length += 4;
968 /* Check the length */
969 if (bufferlength < 0) {
970 expert_add_info_format(pinfo, part_buffer_length_item, &ei_saphdb_buffer_length, "Part Buffer length %d is invalid", bufferlength);
973 /* Align the buffer length to 8 */
974 if (bufferlength % 8 != 0) {
975 bufferlength += 8 - bufferlength % 8;
978 /* Adjust the length */
979 if (bufferlength < 0 || tvb_reported_length_remaining(tvb, offset) < bufferlength) {
980 bufferlength = tvb_reported_length_remaining(tvb, offset);
983 /* Add the part buffer tree and dissect it */
984 if (argcount > 0) {
985 part_buffer_item = proto_tree_add_item(part_tree, hf_saphdb_part_buffer, tvb, offset, bufferlength, ENC_NA);
986 part_buffer_tree = proto_item_add_subtree(part_buffer_item, ett_saphdb);
988 dissect_saphdb_part_buffer(tvb, pinfo, part_buffer_tree, offset, bufferlength, argcount, partkind, partkind_item);
989 length += bufferlength;
992 /* Adjust the item tree length */
993 proto_item_set_len(part_tree, length);
995 return length;
999 static int
1000 dissect_saphdb_segment(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_, uint32_t offset, int16_t number_of_segments, uint16_t nosegment, bool compressed)
1002 int8_t segmentkind = 0, message_type = 0;
1003 int16_t number_of_parts = 0, segment_number = 0, function_code = 0;
1004 uint32_t length = 0, part_length = 0;
1005 int32_t segmentlength = 0;
1006 proto_item *segment_item = NULL, *segmentlength_item = NULL, *number_of_parts_item = NULL, *segment_number_item = NULL, *segment_buffer_item = NULL;
1007 proto_tree *segment_tree = NULL, *segment_buffer_tree = NULL;
1009 /* Add the Segment subtree */
1010 segment_item = proto_tree_add_item(tree, hf_saphdb_segment, tvb, offset, 13, ENC_NA);
1011 segment_tree = proto_item_add_subtree(segment_item, ett_saphdb);
1012 proto_item_append_text(segment_item, " (%d/%d)", nosegment, number_of_segments);
1014 /* Add the Segment fields */
1015 segmentlength = tvb_get_int32(tvb, offset, ENC_LITTLE_ENDIAN);
1016 segmentlength_item = proto_tree_add_item(segment_tree, hf_saphdb_segment_segmentlength, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1017 offset += 4;
1018 length += 4;
1019 proto_tree_add_item(segment_tree, hf_saphdb_segment_segmentofs, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1020 offset += 4;
1021 length += 4;
1022 number_of_parts = tvb_get_int16(tvb, offset, ENC_LITTLE_ENDIAN);
1023 number_of_parts_item = proto_tree_add_item(segment_tree, hf_saphdb_segment_noofparts, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1024 offset += 2;
1025 length += 2;
1026 segment_number = tvb_get_int16(tvb, offset, ENC_LITTLE_ENDIAN);
1027 segment_number_item = proto_tree_add_item(segment_tree, hf_saphdb_segment_segmentno, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1028 offset += 2;
1029 length += 2;
1030 segmentkind = tvb_get_int8(tvb, offset);
1031 proto_tree_add_item(segment_tree, hf_saphdb_segment_segmentkind, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1032 offset += 1;
1033 length += 1;
1035 col_append_fstr(pinfo->cinfo, COL_INFO, "Segment %s (", val_to_str_const(segmentkind, saphdb_segment_segmentkind_vals, "Unknown"));
1036 proto_item_append_text(segment_item, ", %s", val_to_str_const(segmentkind, saphdb_segment_segmentkind_vals, "Unknown"));
1038 /* Check a couple of fields */
1039 if (segmentlength < 13) {
1040 expert_add_info_format(pinfo, segmentlength_item, &ei_saphdb_segment_length, "Segment length %d is invalid", segmentlength);
1042 if (number_of_parts < 0) {
1043 expert_add_info_format(pinfo, number_of_parts_item, &ei_saphdb_parts_number_incorrect, "Number of parts %d is invalid", number_of_parts);
1045 if (segment_number < 0 || nosegment != segment_number) {
1046 expert_add_info_format(pinfo, segment_number_item, &ei_saphdb_segments_incorrect_order, "Segment number %d is invalid (expected %d)", segment_number, nosegment);
1049 /* Add additional fields according to the segment kind*/
1050 switch (segmentkind) {
1051 case 1: /* Request */
1052 message_type = tvb_get_int8(tvb, offset);
1053 col_append_fstr(pinfo->cinfo, COL_INFO, "%s)", val_to_str_const(message_type, saphdb_segment_messagetype_vals, "Unknown"));
1054 proto_item_append_text(segment_item, ", %s", val_to_str_const(message_type, saphdb_segment_messagetype_vals, "Unknown"));
1055 proto_tree_add_item(segment_tree, hf_saphdb_segment_messagetype, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1056 offset += 1;
1057 length += 1;
1059 proto_tree_add_item(segment_tree, hf_saphdb_segment_commit, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1060 offset += 1;
1061 length += 1;
1062 proto_tree_add_item(segment_tree, hf_saphdb_segment_commandoptions, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1063 offset += 1;
1064 length += 1;
1066 proto_tree_add_item(segment_tree, hf_saphdb_segment_reserved, tvb, offset, 8, ENC_NA);
1067 offset += 8;
1068 length += 8;
1069 break;
1070 case 2: /* Reply */
1071 proto_tree_add_item(segment_tree, hf_saphdb_segment_reserved, tvb, offset, 1, ENC_NA);
1072 offset += 1;
1073 length += 1;
1075 function_code = tvb_get_int16(tvb, offset, ENC_LITTLE_ENDIAN);
1076 col_append_fstr(pinfo->cinfo, COL_INFO, "%s)", val_to_str_const(function_code, saphdb_segment_functioncode_vals, "Unknown"));
1077 proto_item_append_text(segment_item, ", %s", val_to_str_const(function_code, saphdb_segment_functioncode_vals, "Unknown"));
1078 proto_tree_add_item(segment_tree, hf_saphdb_segment_functioncode, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1079 offset += 2;
1080 length += 2;
1082 proto_tree_add_item(segment_tree, hf_saphdb_segment_reserved, tvb, offset, 8, ENC_NA);
1083 offset += 8;
1084 length += 8;
1085 break;
1086 default: /* Error and other types */
1087 proto_tree_add_item(segment_tree, hf_saphdb_segment_reserved, tvb, offset, 11, ENC_NA);
1088 offset += 11;
1089 length += 11;
1090 col_append_str(pinfo->cinfo, COL_INFO, ")");
1092 break;
1095 /* If the packet is compressed, compression will apply from here on. As we don't support compression yet, we stop dissecting here. */
1096 if (compressed) {
1097 return length;
1100 /* Add the Segment Buffer subtree */
1101 if (((uint32_t)segmentlength > length) && (number_of_parts > 0)) {
1102 segment_buffer_item = proto_tree_add_item(segment_tree, hf_saphdb_segment_buffer, tvb, offset, segmentlength - length, ENC_NA);
1103 segment_buffer_tree = proto_item_add_subtree(segment_buffer_item, ett_saphdb);
1105 /* Iterate over the parts and dissect them */
1106 for (uint16_t part_number = 1; part_number <= number_of_parts && tvb_reported_length_remaining(tvb, offset) >= 16; part_number++) {
1107 part_length = dissect_saphdb_part(tvb, pinfo, segment_buffer_tree, NULL, offset, number_of_parts, part_number);
1108 offset += part_length;
1109 length += part_length;
1114 /* Adjust the item tree length */
1115 proto_item_set_len(segment_tree, length);
1117 return length;
1121 static int
1122 dissect_saphdb_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1124 uint32_t offset = 0;
1126 /* Add the protocol to the column */
1127 col_set_str(pinfo->cinfo, COL_PROTOCOL, "SAPHDB");
1128 /* Clear out stuff in the info column */
1129 col_clear(pinfo->cinfo,COL_INFO);
1131 /* we are being asked for details */
1132 if (tvb_reported_length(tvb) == 8 || tvb_reported_length(tvb) == 14 || tvb_reported_length(tvb) >= SAPHDB_HEADER_LEN) {
1134 proto_item *ti = NULL;
1135 proto_tree *saphdb_tree = NULL;
1137 /* Add the main saphdb subtree */
1138 ti = proto_tree_add_item(tree, proto_saphdb, tvb, offset, -1, ENC_NA);
1139 saphdb_tree = proto_item_add_subtree(ti, ett_saphdb);
1142 /* Initialization Request message */
1143 if (tvb_reported_length(tvb) == 14) {
1144 proto_tree_add_item(saphdb_tree, hf_saphdb_initialization_request, tvb, offset, 14, ENC_NA);
1145 offset += 14;
1146 col_set_str(pinfo->cinfo, COL_INFO, "Initialization Request");
1148 /* Initialization Reply message */
1149 } else if (tvb_reported_length(tvb) == 8) {
1150 proto_item *initialization_reply = NULL;
1151 proto_tree *initialization_reply_tree = NULL;
1153 /* Add the Initialization Reply subtree */
1154 initialization_reply = proto_tree_add_item(saphdb_tree, hf_saphdb_initialization_reply, tvb, offset, 8, ENC_NA);
1155 initialization_reply_tree = proto_item_add_subtree(initialization_reply, ett_saphdb);
1157 proto_tree_add_item(initialization_reply_tree, hf_saphdb_initialization_reply_product_version_major, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1158 offset += 1;
1159 proto_tree_add_item(initialization_reply_tree, hf_saphdb_initialization_reply_product_version_minor, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1160 offset += 2;
1161 proto_tree_add_item(initialization_reply_tree, hf_saphdb_initialization_reply_protocol_version_major, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1162 offset += 1;
1163 proto_tree_add_item(initialization_reply_tree, hf_saphdb_initialization_reply_protocol_version_minor, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1164 offset += 2;
1166 col_set_str(pinfo->cinfo, COL_INFO, "Initialization Reply");
1168 /* All other message types */
1169 } else if (tvb_reported_length(tvb) >= SAPHDB_HEADER_LEN) {
1171 bool compressed = false;
1172 int16_t number_of_segments = 0;
1173 uint32_t varpartlength = 0;
1174 proto_item *message_header_item = NULL, *varpartlength_item = NULL, *number_of_segments_item = NULL, *message_buffer_item = NULL, *compressed_buffer_item = NULL;
1175 proto_tree *message_header_tree = NULL, *message_buffer_tree = NULL;
1177 /* Add the Message Header subtree */
1178 message_header_item = proto_tree_add_item(saphdb_tree, hf_saphdb_message_header, tvb, offset, SAPHDB_HEADER_LEN, ENC_NA);
1179 message_header_tree = proto_item_add_subtree(message_header_item, ett_saphdb);
1181 /* Add the Message Header fields */
1182 proto_tree_add_item(message_header_tree, hf_saphdb_message_header_sessionid, tvb, offset, 8, ENC_LITTLE_ENDIAN);
1183 offset += 8;
1184 proto_tree_add_item(message_header_tree, hf_saphdb_message_header_packetcount, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1185 offset += 4;
1186 varpartlength_item = proto_tree_add_item_ret_uint(message_header_tree, hf_saphdb_message_header_varpartlength, tvb, offset, 4, ENC_LITTLE_ENDIAN, &varpartlength);
1187 offset += 4;
1188 proto_tree_add_item(message_header_tree, hf_saphdb_message_header_varpartsize, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1189 offset += 4;
1190 number_of_segments = tvb_get_int16(tvb, offset, ENC_LITTLE_ENDIAN);
1191 number_of_segments_item = proto_tree_add_item(message_header_tree, hf_saphdb_message_header_noofsegm, tvb, offset, 2, ENC_LITTLE_ENDIAN);
1192 offset += 2;
1193 compressed = tvb_get_int8(tvb, offset) == 2;
1194 proto_tree_add_item(message_header_tree, hf_saphdb_message_header_packetoptions, tvb, offset, 1, ENC_LITTLE_ENDIAN);
1195 offset += 1;
1196 proto_tree_add_item(message_header_tree, hf_saphdb_message_header_reserved, tvb, offset, 1, ENC_NA);
1197 offset += 1;
1198 proto_tree_add_item(message_header_tree, hf_saphdb_message_header_compressionvarpartlength, tvb, offset, 4, ENC_LITTLE_ENDIAN);
1199 offset += 4;
1200 proto_tree_add_item(message_header_tree, hf_saphdb_message_header_reserved, tvb, offset, 4, ENC_NA);
1201 offset += 4;
1203 /* Check the length of the variable part against the remaining packet */
1204 if ((uint32_t)tvb_reported_length_remaining(tvb, offset) != varpartlength) {
1205 expert_add_info_format(pinfo, varpartlength_item, &ei_saphdb_varpartlenght_incorrect, "Length of variable part %d is invalid", varpartlength);
1206 varpartlength = tvb_reported_length_remaining(tvb, offset);
1209 /* Add the Message Buffer subtree */
1210 if (varpartlength > 0 && number_of_segments > 0) {
1211 message_buffer_item = proto_tree_add_item(saphdb_tree, hf_saphdb_message_buffer, tvb, offset, varpartlength, ENC_NA);
1212 message_buffer_tree = proto_item_add_subtree(message_buffer_item, ett_saphdb);
1214 /* If the packet is compressed, the message header and the first segment header is sent uncompressed. We dissect the
1215 * first segment only and add a new item with the compressed buffer. Adding an expert warning as well. */
1216 if (compressed) {
1217 offset += dissect_saphdb_segment(tvb, pinfo, message_buffer_tree, NULL, offset, number_of_segments, 1, compressed);
1218 compressed_buffer_item = proto_tree_add_item(message_buffer_tree, hf_saphdb_compressed_buffer, tvb, offset, varpartlength, ENC_NA);
1219 if (global_saphdb_highlight_items){
1220 expert_add_info_format(pinfo, compressed_buffer_item, &ei_saphdb_compressed_unknown, "Packet is compressed and decompression is not supported");
1223 } else {
1224 /* Iterate over the segments and dissect them */
1225 for (uint16_t segment_number = 1; segment_number <= number_of_segments && tvb_reported_length_remaining(tvb, offset) >= 13; segment_number++) {
1226 offset += dissect_saphdb_segment(tvb, pinfo, message_buffer_tree, NULL, offset, number_of_segments, segment_number, compressed);
1230 } else {
1231 expert_add_info_format(pinfo, number_of_segments_item, &ei_saphdb_segments_number_incorrect, "Number of segments %d is invalid", number_of_segments);
1238 return offset;
1241 static unsigned
1242 get_saphdb_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
1244 /* Entire HDB packets are of 32-bytes header plus the value in varpartlength field */
1245 uint32_t varpartlength = tvb_get_uint32(tvb, offset + 12, ENC_LITTLE_ENDIAN);
1246 return varpartlength + SAPHDB_HEADER_LEN;
1249 static int
1250 dissect_saphdb_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1252 return dissect_saphdb_message(tvb, pinfo, tree, NULL);
1255 static int
1256 dissect_saphdb(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
1258 if (tvb_reported_length(tvb) == 14 || tvb_reported_length(tvb) == 8) {
1259 return dissect_saphdb_tcp(tvb, pinfo, tree, data);
1261 else
1263 /* Header must be present */
1264 if (!tvb_bytes_exist(tvb, 0, SAPHDB_HEADER_LEN))
1265 return 0;
1267 /* Filter on reserved bytes */
1268 if(tvb_get_uint8(tvb, 23) || tvb_get_uint32(tvb, 28, ENC_BIG_ENDIAN))
1269 return 0;
1271 tcp_dissect_pdus(tvb, pinfo, tree, true, SAPHDB_HEADER_LEN, get_saphdb_pdu_len, dissect_saphdb_tcp, data);
1273 return tvb_reported_length(tvb);
1276 void
1277 proto_register_saphdb(void)
1279 static hf_register_info hf[] = {
1280 /* Initialization items */
1281 { &hf_saphdb_initialization_request,
1282 { "Initialization Request", "saphdb.init_request", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1284 { &hf_saphdb_initialization_reply,
1285 { "Initialization Reply", "saphdb.init_reply", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1286 { &hf_saphdb_initialization_reply_product_version_major,
1287 { "Product Version Major", "saphdb.init_reply.product_version.major", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1288 { &hf_saphdb_initialization_reply_product_version_minor,
1289 { "Product Version Minor", "saphdb.init_reply.product_version.minor", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1290 { &hf_saphdb_initialization_reply_protocol_version_major,
1291 { "Protocol Version Major", "saphdb.init_reply.protocol_version.major", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1292 { &hf_saphdb_initialization_reply_protocol_version_minor,
1293 { "Protocol Version Minor", "saphdb.init_reply.protocol_version.minor", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1295 /* Message Header items */
1296 { &hf_saphdb_message_header,
1297 { "Message Header", "saphdb.message_header", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1298 { &hf_saphdb_message_header_sessionid,
1299 { "Session ID", "saphdb.sessionid", FT_INT64, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1300 { &hf_saphdb_message_header_packetcount,
1301 { "Packet Count", "saphdb.packetcount", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1302 { &hf_saphdb_message_header_varpartlength,
1303 { "Var Part Length", "saphdb.varpartlength", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1304 { &hf_saphdb_message_header_varpartsize,
1305 { "Var Part Size", "saphdb.varpartsize", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1306 { &hf_saphdb_message_header_noofsegm,
1307 { "Number of Segments", "saphdb.noofsegm", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1308 { &hf_saphdb_message_header_packetoptions,
1309 { "Packet Options", "saphdb.packetoptions", FT_INT8, BASE_DEC, VALS(saphdb_message_header_packetoptions_vals), 0x0, NULL, HFILL }},
1310 { &hf_saphdb_message_header_compressionvarpartlength,
1311 { "Compression Var Part Length", "saphdb.compressionvarpartlength", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1312 { &hf_saphdb_message_header_reserved,
1313 { "Reserved", "saphdb.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1314 /* Message Buffer items */
1315 { &hf_saphdb_message_buffer,
1316 { "Message Buffer", "saphdb.messagebuffer", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1317 { &hf_saphdb_compressed_buffer,
1318 { "Compressed Buffer", "saphdb.compressedbuffer", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1320 /* Segment items */
1321 { &hf_saphdb_segment,
1322 { "Segment", "saphdb.segment", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1323 { &hf_saphdb_segment_segmentlength,
1324 { "Segment Length", "saphdb.segment.length", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1325 { &hf_saphdb_segment_segmentofs,
1326 { "Segment Offset", "saphdb.segment.offset", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1327 { &hf_saphdb_segment_noofparts,
1328 { "Number of Parts", "saphdb.segment.noofparts", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1329 { &hf_saphdb_segment_segmentno,
1330 { "Segment Number", "saphdb.segment.segmentno", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1331 { &hf_saphdb_segment_segmentkind,
1332 { "Segment Kind", "saphdb.segment.kind", FT_INT8, BASE_DEC, VALS(saphdb_segment_segmentkind_vals), 0x0, NULL, HFILL }},
1333 { &hf_saphdb_segment_messagetype,
1334 { "Message Type", "saphdb.segment.messagetype", FT_INT8, BASE_DEC, VALS(saphdb_segment_messagetype_vals), 0x0, NULL, HFILL }},
1335 { &hf_saphdb_segment_commit,
1336 { "Commit", "saphdb.segment.commit", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1337 { &hf_saphdb_segment_commandoptions,
1338 { "Command Options", "saphdb.segment.commandoptions", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1339 { &hf_saphdb_segment_functioncode,
1340 { "Function Code", "saphdb.segment.functioncode", FT_INT16, BASE_DEC, VALS(saphdb_segment_functioncode_vals), 0x0, NULL, HFILL }},
1341 { &hf_saphdb_segment_reserved,
1342 { "Reserved", "saphdb.segment.reserved", FT_BYTES, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1344 /* Segment Buffer items */
1345 { &hf_saphdb_segment_buffer,
1346 { "Segment Buffer", "saphdb.segment.buffer", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1348 /* Part items */
1349 { &hf_saphdb_part,
1350 { "Part", "saphdb.segment.part", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1351 { &hf_saphdb_part_partkind,
1352 { "Part Kind", "saphdb.segment.part.partkind", FT_INT8, BASE_DEC, VALS(saphdb_part_partkind_vals), 0x0, NULL, HFILL }},
1353 { &hf_saphdb_part_partattributes,
1354 { "Part Attributes", "saphdb.segment.part.partattributes", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1355 { &hf_saphdb_part_argumentcount,
1356 { "Argument Count", "saphdb.segment.part.argumentcount", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1357 { &hf_saphdb_part_bigargumentcount,
1358 { "Big Argument Count", "saphdb.segment.part.bigargumentcount", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1359 { &hf_saphdb_part_bufferlength,
1360 { "Buffer Length", "saphdb.segment.part.bufferlength", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1361 { &hf_saphdb_part_buffersize,
1362 { "Buffer Size", "saphdb.segment.part.buffersize", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1364 /* Part Buffer items */
1365 { &hf_saphdb_part_buffer,
1366 { "Part Buffer", "saphdb.segment.part.buffer", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1368 /* Part Buffer Option Part Data items */
1369 { &hf_saphdb_part_option_argcount,
1370 { "Argument Row Count", "saphdb.segment.part.option.argcount", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1371 { &hf_saphdb_part_option_name,
1372 { "Option Name", "saphdb.segment.part.option.name", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1373 { &hf_saphdb_part_option_type,
1374 { "Option Type", "saphdb.segment.part.option.type", FT_INT8, BASE_DEC, VALS(saphdb_part_type_vals), 0x0, NULL, HFILL }},
1375 { &hf_saphdb_part_option_length,
1376 { "Option Length", "saphdb.segment.part.option.length", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1377 { &hf_saphdb_part_option_value,
1378 { "Option Value", "saphdb.segment.part.option.value", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1379 { &hf_saphdb_part_option_value_bool,
1380 { "Option Value", "saphdb.segment.part.option.value.bool", FT_BOOLEAN, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1381 { &hf_saphdb_part_option_value_byte,
1382 { "Option Value", "saphdb.segment.part.option.value.byte", FT_INT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1383 { &hf_saphdb_part_option_value_short,
1384 { "Option Value", "saphdb.segment.part.option.value.short", FT_INT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1385 { &hf_saphdb_part_option_value_int,
1386 { "Option Value", "saphdb.segment.part.option.value.int", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1387 { &hf_saphdb_part_option_value_bigint,
1388 { "Option Value", "saphdb.segment.part.option.value.bigint", FT_INT64, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1389 { &hf_saphdb_part_option_value_string,
1390 { "Option Value", "saphdb.segment.part.option.value.string", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1391 { &hf_saphdb_part_option_value_double,
1392 { "Option Value", "saphdb.segment.part.option.value.double", FT_DOUBLE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1394 /* SAP HDB Part Buffer COMMAND items */
1395 { &hf_saphdb_part_command,
1396 { "Command", "saphdb.segment.part.command", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1398 /* SAP HDB Part Buffer ERROR items */
1399 { &hf_saphdb_part_error_code,
1400 { "Error Code", "saphdb.segment.part.error.code", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1401 { &hf_saphdb_part_error_position,
1402 { "Error Position", "saphdb.segment.part.error.position", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1403 { &hf_saphdb_part_error_text_length,
1404 { "Error Text Length", "saphdb.segment.part.error.text_length", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1405 { &hf_saphdb_part_error_level,
1406 { "Error Level", "saphdb.segment.part.error.level", FT_INT8, BASE_DEC, VALS(saphdb_error_level_vals), 0x0, NULL, HFILL }},
1407 { &hf_saphdb_part_error_sqlstate,
1408 { "SQL State", "saphdb.segment.part.error.sqlstate", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1409 { &hf_saphdb_part_error_text,
1410 { "Error Text", "saphdb.segment.part.error.text", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1412 /* Part Buffer AUTHENTICATION items */
1413 { &hf_saphdb_part_authentication_field_count,
1414 { "Field Count", "saphdb.segment.part.authentication.fieldcount", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1415 { &hf_saphdb_part_authentication_field_length,
1416 { "Field Length", "saphdb.segment.part.authentication.fieldlength", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1417 { &hf_saphdb_part_authentication_field_value,
1418 { "Field Value", "saphdb.segment.part.authentication.fieldvalue", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1420 /* SAP HDB Part Buffer CLIENTID items */
1421 { &hf_saphdb_part_clientid,
1422 { "Client ID", "saphdb.segment.part.clientid", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1426 /* Setup protocol subtree array */
1427 static int *ett[] = {
1428 &ett_saphdb
1431 /* Register the expert info */
1432 static ei_register_info ei[] = {
1433 { &ei_saphdb_compressed_unknown, { "saphdb.compressed", PI_UNDECODED, PI_WARN, "The packet is compressed, and decompression is not supported", EXPFILL }},
1434 { &ei_saphdb_option_part_unknown, { "saphdb.segment.part.option.unknown", PI_UNDECODED, PI_WARN, "The Option Part has a unknown type that is not dissected", EXPFILL }},
1435 { &ei_saphdb_segments_incorrect_order, { "saphdb.segment.segmentno.invalid", PI_MALFORMED, PI_ERROR, "The segments are in incorrect order or are invalid", EXPFILL }},
1436 { &ei_saphdb_segments_number_incorrect, { "saphdb.noofsegm.invalid", PI_MALFORMED, PI_ERROR, "The number of segments is incorrect", EXPFILL }},
1437 { &ei_saphdb_segment_length, { "saphdb.segment.segmentlength.invalid", PI_MALFORMED, PI_ERROR, "The segment length is incorrect", EXPFILL }},
1438 { &ei_saphdb_buffer_length, { "saphdb.segment.part.bufferlength.invalid", PI_MALFORMED, PI_ERROR, "The part buffer length is incorrect", EXPFILL }},
1439 { &ei_saphdb_parts_number_incorrect, { "saphdb.segment.noofparts.invalid", PI_MALFORMED, PI_ERROR, "The number of parts is incorrect", EXPFILL }},
1440 { &ei_saphdb_varpartlenght_incorrect, { "saphdb.varpartlength.invalid", PI_MALFORMED, PI_ERROR, "The length is incorrect", EXPFILL }},
1443 module_t *saphdb_module;
1444 expert_module_t* saphdb_expert;
1446 /* Register the protocol */
1447 proto_saphdb = proto_register_protocol("SAP HANA SQL Command Network Protocol", "SAPHDB", "saphdb");
1449 saphdb_expert = expert_register_protocol(proto_saphdb);
1450 expert_register_field_array(saphdb_expert, ei, array_length(ei));
1452 saphdb_handle = register_dissector("saphdb", dissect_saphdb, proto_saphdb);
1454 proto_register_field_array(proto_saphdb, hf, array_length(hf));
1455 proto_register_subtree_array(ett, array_length(ett));
1457 /* Register the preferences */
1458 saphdb_module = prefs_register_protocol(proto_saphdb, proto_reg_handoff_saphdb);
1460 range_convert_str(wmem_epan_scope(), &global_saphdb_port_range, SAPHDB_PORT_RANGE, MAX_TCP_PORT);
1461 prefs_register_range_preference(saphdb_module, "tcp_ports", "SAP HANA SQL Command Network Protocol port numbers", "Port numbers used for SAP HANA SQL Command Network Protocol (default " SAPHDB_PORT_RANGE ")", &global_saphdb_port_range, MAX_TCP_PORT);
1463 prefs_register_bool_preference(saphdb_module, "highlight_unknown_items", "Highlight unknown SAP HANA HDB items", "Whether the SAP HANA HDB Protocol dissector should highlight unknown items (might be noise and generate a lot of expert warnings)", &global_saphdb_highlight_items);
1468 * Helpers for dealing with the port range
1470 static void range_delete_callback (uint32_t port, void *ptr _U_)
1472 dissector_delete_uint("tcp.port", port, saphdb_handle);
1474 static void range_add_callback (uint32_t port, void *ptr _U_)
1476 dissector_add_uint("tcp.port", port, saphdb_handle);
1480 * Register Hand off for the SAP HDB Protocol
1482 void
1483 proto_reg_handoff_saphdb(void)
1485 static bool initialized = false;
1486 static range_t *saphdb_port_range;
1488 if (!initialized) {
1489 saphdb_handle = create_dissector_handle(dissect_saphdb, proto_saphdb);
1490 saphdb_handle_tls = register_dissector_with_description("saphdb_tls", "SAPHDB over TLS", dissect_saphdb, proto_saphdb);
1491 initialized = true;
1492 } else {
1493 range_foreach(saphdb_port_range, range_delete_callback, NULL);
1494 wmem_free(wmem_epan_scope(), saphdb_port_range);
1497 saphdb_port_range = range_copy(wmem_epan_scope(), global_saphdb_port_range);
1498 range_foreach(saphdb_port_range, range_add_callback, NULL);
1499 ssl_dissector_add(0, saphdb_handle_tls);
1501 gssapi_handle = find_dissector_add_dependency("gssapi", proto_saphdb);
1506 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1508 * Local variables:
1509 * c-basic-offset: 8
1510 * tab-width: 8
1511 * indent-tabs-mode: t
1512 * End:
1514 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1515 * :indentSize=8:tabSize=8:noTabs=false: