Coverage Report

Created: 2025-12-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/epan/dissectors/packet-saprouter.c
Line
Count
Source
1
/* packet-saprouter.c
2
 * Routines for SAP Router dissection
3
 * Copyright 2022, Martin Gallo <martin.gallo [AT] gmail.com>
4
 * Code contributed by SecureAuth Corp.
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
/*
14
 * This is a dissector for the SAP Router protocol.
15
 *
16
 * Some details and example requests can be found in pysap's documentation: https://pysap.readthedocs.io/en/latest/protocols/SAPRouter.html.
17
 */
18
19
#include <config.h>
20
#include <stdlib.h>
21
22
#include <epan/packet.h>
23
#include <epan/prefs.h>
24
#include <epan/expert.h>
25
#include <wsutil/wmem/wmem.h>
26
#include <epan/conversation.h>
27
28
#include <epan/tap.h>
29
#include <ui/tap-credentials.h>
30
31
#include "packet-sapni.h"
32
#include "packet-sapsnc.h"
33
34
35
/* Define default ports */
36
14
#define SAPROUTER_PORT_RANGE "3298-3299"
37
38
/*
39
 * Length of the frame header
40
 */
41
#define SAPROUTER_HEADER_LEN  8
42
43
/*
44
 * Offsets of header fields
45
 */
46
0
#define SAPROUTER_ROUTE_LENGTH_OFFSET 16
47
0
#define SAPROUTER_ROUTE_OFFSET_OFFSET 20
48
49
/* SAP Router Eye Catcher strings */
50
0
#define SAPROUTER_TYPE_NIPING_STRING "EYECATCHER"
51
0
#define SAPROUTER_TYPE_ROUTE_STRING "NI_ROUTE"
52
0
#define SAPROUTER_TYPE_ROUTE_ACCEPT "NI_PONG"
53
0
#define SAPROUTER_TYPE_ERR_STRING "NI_RTERR"
54
0
#define SAPROUTER_TYPE_ADMIN_STRING "ROUTER_ADM"
55
56
/* SAP Router Talk Modes */
57
static const value_string saprouter_talk_mode_vals[] = {
58
  { 0, "NI_MSG_IO" },
59
  { 1, "NI_RAW_IO" },
60
  { 2, "NI_ROUT_IO" },
61
  /* NULL */
62
  { 0, NULL},
63
};
64
65
/* SAP Router Operation values */
66
static const value_string saprouter_opcode_vals[] = {
67
  { 0, "Error information" },
68
  { 1, "Version Request" },
69
  { 2, "Version Response" },
70
  { 5, "Send Handle (5)" },   /* TODO: Check this opcodes */
71
  { 6, "Send Handle (6)" },   /* TODO: Check this opcodes */
72
  { 8, "Send Handle (8)" },   /* TODO: Check this opcodes */
73
  { 70, "SNC request" },      /* TODO: Check this opcodes NiSncOpcode: NISNC_REQ */
74
  { 71, "SNC handshake complete" }, /* TODO: Check this opcodes NiSncOpcode: NISNC_ACK */
75
  /* NULL */
76
  { 0, NULL}
77
};
78
79
/* SAP Router Return Code values (as per SAP Note 63342 https://launchpad.support.sap.com/#/notes/63342) */
80
static const value_string saprouter_return_code_vals[] = {
81
  { -1, "NI-internal error (NIEINTERN)" },
82
  { -2, "Host name unknown (NIEHOST_UNKNOWN)" },
83
  { -3, "Service unknown (NIESERV_UNKNOWN)" },
84
  { -4, "Service already used (NIESERV_USED)" },
85
  { -5, "Time limit reached (NIETIMEOUT)" },
86
  { -6, "Connection to partner broken (NIECONN_BROKEN)" },
87
  { -7, "Data range too small (NIETOO_SMALL)" },
88
  { -8, "Invalid parameters (NIEINVAL)" },
89
  { -9, "Wake-Up (without data) (NIEWAKEUP)" },
90
  {-10, "Connection setup failed (NIECONN_REFUSED)" },
91
  {-11, "PING/PONG signal received (NIEPING)" },
92
  {-12, "Connection to partner via NiRouter not yet set up (NIECONN_PENDING)" },
93
  {-13, "Invalid version (NIEVERSION)" },
94
  {-14, "Local hostname cannot be found (NIEMYHOSTNAME)" },
95
  {-15, "No free port in range (NIENOFREEPORT)" },
96
  {-16, "Local hostname invalid (NIEMYHOST_VERIFY)" },
97
  {-17, "Error in the SNC shift in the saprouter ==> (NIESNC_FAILURE)" },
98
  {-18, "Opcode received (NIEOPCODE)" },
99
  {-19, "queue limit reached, next package not accepted (NIEQUE_FULL)" },
100
  {-20, "Requested package too large (NIETOO_BIG)" },
101
  {-90, "Host name unknown (NIEROUT_HOST_UNKNOWN)" },
102
  {-91, "Service unknown (NIEROUT_SERV_UNKNOWN)" },
103
  {-92, "Connection setup failed (NIEROUT_CONN_REFUSED)" },
104
  {-93, "NI-internal errors (NIEROUT_INTERN)" },
105
  {-94, "Connect from source to destination not allowed (NIEROUT_PERM_DENIED)" },
106
  {-95, "Connection terminated (NIEROUT_CONN_BROKEN)" },
107
  {-96, "Invalid client version (NIEROUT_VERSION)" },
108
  {-97, "Connection cancelled by administrator (NIEROUT_CANCELED)" },
109
  {-98, "saprouter shutdown (NIEROUT_SHUTDOWN)" },
110
  {-99, "Information request refused (NIEROUT_INFO_DENIED)" },
111
  {-100, "Max. number of clients reached (NIEROUT_OVERFLOW)" },
112
  {-101, "Talkmode not allowed (NIEROUT_MODE_DENIED)" },
113
  {-102, "Client not available (NIEROUT_NOCLIENT)" },
114
  {-103, "Error in external library (NIEROUT_EXTERN)" },
115
  {-104, "Error in the SNC shift (NIEROUT_SNC_FAILURE)" },
116
  /* NULL */
117
  { 0, NULL}
118
};
119
120
121
/* SAP Router Admin Command values */
122
static const value_string saprouter_admin_command_vals[] = {
123
  { 2, "Information Request" },
124
  { 3, "New Route Table Request" },
125
  { 4, "Toggle Trace Request" },
126
  { 5, "Stop Request" },
127
  { 6, "Cancel Route Request" },
128
  { 7, "Dump Buffers Request" },
129
  { 8, "Flush Buffers Request" },
130
  { 9, "Soft Shutdown Request" },
131
  { 10, "Set Trace Peer" },
132
  { 11, "Clear Trace Peer" },
133
  { 12, "Trace Connection" },
134
  { 13, "Trace Connection" },
135
  { 14, "Hide Error Information Request" },
136
  /* NULL */
137
  { 0, NULL}
138
};
139
140
static int credentials_tap;
141
142
static int proto_saprouter;
143
144
/* General fields */
145
static int hf_saprouter_type;
146
static int hf_saprouter_ni_version;
147
148
/* Niping messages */
149
static int hf_saprouter_niping_message;
150
151
/* Route information */
152
static int hf_saprouter_route_version;
153
static int hf_saprouter_entries;
154
static int hf_saprouter_talk_mode;
155
static int hf_saprouter_rest_nodes;
156
static int hf_saprouter_route_length;
157
static int hf_saprouter_route_offset;
158
static int hf_saprouter_route;
159
static int hf_saprouter_route_string;
160
161
static int hf_saprouter_route_requested_in;
162
static int hf_saprouter_route_accepted_in;
163
164
/* Route strings */
165
static int hf_saprouter_route_string_hostname;
166
static int hf_saprouter_route_string_service;
167
static int hf_saprouter_route_string_password;
168
169
170
/* Error Information/Control Messages */
171
static int hf_saprouter_opcode;
172
static int hf_saprouter_return_code;
173
static int hf_saprouter_unknown;
174
175
/* Error Information Messages */
176
static int hf_saprouter_error_length;
177
static int hf_saprouter_error_string;
178
static int hf_saprouter_error_eyecatcher;
179
static int hf_saprouter_error_counter;
180
static int hf_saprouter_error_error;
181
static int hf_saprouter_error_return_code;
182
static int hf_saprouter_error_component;
183
static int hf_saprouter_error_release;
184
static int hf_saprouter_error_version;
185
static int hf_saprouter_error_module;
186
static int hf_saprouter_error_line;
187
static int hf_saprouter_error_detail;
188
static int hf_saprouter_error_time;
189
static int hf_saprouter_error_system_call;
190
static int hf_saprouter_error_errorno;
191
static int hf_saprouter_error_errorno_text;
192
static int hf_saprouter_error_error_count;
193
static int hf_saprouter_error_location;
194
static int hf_saprouter_error_unknown;  /* TODO: Unknown fields */
195
196
/* Control Messages */
197
static int hf_saprouter_control_length;
198
static int hf_saprouter_control_string;
199
static int hf_saprouter_control_unknown;
200
201
/* Admin Messages */
202
static int hf_saprouter_admin_command;
203
static int hf_saprouter_admin_password;
204
static int hf_saprouter_admin_client_count_short;
205
static int hf_saprouter_admin_client_count_int;
206
static int hf_saprouter_admin_client_ids;
207
static int hf_saprouter_admin_client_id;
208
static int hf_saprouter_admin_address_mask;
209
210
static int ett_saprouter;
211
212
/* Expert info */
213
static expert_field ei_saprouter_route_password_found;
214
static expert_field ei_saprouter_route_invalid_length;
215
static expert_field ei_saprouter_info_password_found;
216
static expert_field ei_saprouter_invalid_client_ids;
217
218
/* Global port preference */
219
static range_t *global_saprouter_port_range;
220
221
222
/* Global SNC dissection preference */
223
static bool global_saprouter_snc_dissection = true;
224
225
/* Protocol handle */
226
static dissector_handle_t saprouter_handle;
227
228
/* Session state information being tracked in a SAP Router conversation */
229
typedef struct saprouter_session_state {
230
  bool route_information;
231
  unsigned   route_requested_in;
232
  bool route_accepted;
233
  unsigned   route_accepted_in;
234
  bool route_snc_protected;
235
  char  *src_hostname;      /* Source hostname (first entry in the route string) */
236
  uint32_t src_port;        /* Source port number */
237
  char  *src_password;      /* Source password XXX: Check if possible */
238
  char  *dest_hostname;     /* Destination hostname (last entry in the route string) */
239
  uint32_t dest_port;       /* Destination port number */
240
  char  *dest_password;     /* Destination password */
241
} saprouter_session_state;
242
243
/*
244
 *
245
 */
246
void proto_reg_handoff_saprouter(void);
247
void proto_register_saprouter(void);
248
249
250
static uint32_t
251
0
dissect_serviceport(char *port){
252
0
  uint32_t portnumber = 0;
253
254
0
  if (g_ascii_isdigit(port[0])){
255
0
    portnumber = (uint32_t)strtoul(port, NULL, 10);
256
0
  } else if ((strlen(port)>5) && g_str_has_prefix(port, "sapdp")){
257
0
    portnumber = 3200 + (uint32_t)strtoul(port+5, NULL, 10);
258
0
  } else if ((strlen(port)>5) && g_str_has_prefix(port, "sapgw")){
259
0
    portnumber = 3300 + (uint32_t)strtoul(port+5, NULL, 10);
260
0
  } else if ((strlen(port)>5) && g_str_has_prefix(port, "sapms")){
261
0
    portnumber = 3600 + (uint32_t)strtoul(port+5, NULL, 10);
262
0
  }
263
0
  return (portnumber);
264
0
}
265
266
static void
267
0
dissect_routestring(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset, saprouter_session_state *session_state){
268
0
  int hop = 1;
269
0
  uint32_t len, route_offset, int_port = 0;
270
0
  char *hostname = NULL, *port = NULL, *password = NULL;
271
0
  proto_item *route_hop = NULL, *route_password = NULL;
272
0
  proto_tree *route_hop_tree = NULL;
273
274
0
  while (tvb_offset_exists(tvb, offset)){
275
0
    route_offset = offset; hostname = port = password = NULL;
276
277
    /* Create the subtree for this route hop */
278
0
    route_hop = proto_tree_add_item(tree, hf_saprouter_route_string, tvb, offset, 0, ENC_NA);
279
0
    route_hop_tree = proto_item_add_subtree(route_hop, ett_saprouter);
280
0
    proto_item_append_text(route_hop, ", nro %d", hop);
281
282
    /* Dissect the hostname string */
283
0
    len = tvb_strsize(tvb, offset);
284
0
    hostname = (char *)tvb_get_string_enc(wmem_file_scope(), tvb, offset, len - 1, ENC_ASCII);
285
0
    proto_tree_add_item(route_hop_tree, hf_saprouter_route_string_hostname, tvb, offset, len, ENC_ASCII);
286
0
    offset += len;
287
288
    /* Dissect the port string */
289
0
    len = tvb_strsize(tvb, offset);
290
0
    port = (char *)tvb_get_string_enc(pinfo->pool, tvb, offset, len - 1, ENC_ASCII);
291
0
    proto_tree_add_item(route_hop_tree, hf_saprouter_route_string_service, tvb, offset, len, ENC_ASCII);
292
0
    offset += len;
293
294
    /* Dissect the password string */
295
0
    len = tvb_strsize(tvb, offset);
296
0
    password = (char *)tvb_get_string_enc(wmem_file_scope(), tvb, offset, len - 1, ENC_ASCII);
297
0
    route_password = proto_tree_add_item(route_hop_tree, hf_saprouter_route_string_password, tvb, offset, len, ENC_ASCII);
298
299
    /* If a password was found, add a expert warning in the security category */
300
0
    if (len > 1){
301
0
      expert_add_info(pinfo, route_password, &ei_saprouter_route_password_found);
302
303
      /* Add the password to the credential tap */
304
0
      tap_credential_t *auth =  wmem_new0(pinfo->pool, tap_credential_t);
305
0
      auth->num = pinfo->num;
306
0
      auth->password_hf_id = hf_saprouter_route_string_password;
307
0
      auth->proto = "SAP Router Route String password";
308
0
      auth->username = wmem_strdup(pinfo->pool, TAP_CREDENTIALS_PLACEHOLDER);
309
0
      tap_queue_packet(credentials_tap, pinfo, auth);
310
0
    }
311
0
    offset += len;
312
313
    /* Adjust the size of the route hop item now that we know the size */
314
0
    proto_item_set_len(route_hop, offset - route_offset);
315
316
    /* Get the service port in numeric format */
317
0
    int_port = dissect_serviceport(port);
318
319
    /* Add the first hostname/port as source in the conversation state*/
320
0
    if ((hop==1) && !(pinfo->fd->visited)){
321
0
      session_state->src_hostname = hostname;
322
0
      session_state->src_port = int_port;
323
0
      session_state->src_password = password;
324
0
    }
325
0
    hop++;
326
0
  }
327
328
0
  if (!(pinfo->fd->visited)) {
329
    /* Add the last hostname/port as destination */
330
0
    if (hop!=1){
331
0
      session_state->dest_hostname = hostname;
332
0
      session_state->dest_port = int_port;
333
0
      session_state->dest_password = password;
334
0
    }
335
    /* Save the status of the conversation state */
336
0
    session_state->route_information = true;
337
0
    session_state->route_accepted = false;
338
0
  }
339
340
0
}
341
342
static void
343
dissect_errorstring(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
344
0
{
345
0
  uint32_t len;
346
347
0
  len = tvb_strsize(tvb, offset);
348
0
  proto_tree_add_item(tree, hf_saprouter_error_eyecatcher, tvb, offset, len, ENC_ASCII);
349
0
  offset += len;
350
0
  len = tvb_strsize(tvb, offset);
351
0
  proto_tree_add_item(tree, hf_saprouter_error_counter, tvb, offset, len, ENC_ASCII);
352
0
  offset += len;
353
0
  len = tvb_strsize(tvb, offset);
354
0
  proto_tree_add_item(tree, hf_saprouter_error_error, tvb, offset, len, ENC_ASCII);
355
0
  offset += len;
356
0
  len = tvb_strsize(tvb, offset);
357
0
  proto_tree_add_item(tree, hf_saprouter_error_return_code, tvb, offset, len, ENC_ASCII);
358
0
  offset += len;
359
0
  len = tvb_strsize(tvb, offset);
360
0
  proto_tree_add_item(tree, hf_saprouter_error_component, tvb, offset, len, ENC_ASCII);
361
0
  offset += len;
362
0
  len = tvb_strsize(tvb, offset);
363
0
  proto_tree_add_item(tree, hf_saprouter_error_release, tvb, offset, len, ENC_ASCII);
364
0
  offset += len;
365
0
  len = tvb_strsize(tvb, offset);
366
0
  proto_tree_add_item(tree, hf_saprouter_error_version, tvb, offset, len, ENC_ASCII);
367
0
  offset += len;
368
0
  len = tvb_strsize(tvb, offset);
369
0
  proto_tree_add_item(tree, hf_saprouter_error_module, tvb, offset, len, ENC_ASCII);
370
0
  offset += len;
371
0
  len = tvb_strsize(tvb, offset);
372
0
  proto_tree_add_item(tree, hf_saprouter_error_line, tvb, offset, len, ENC_ASCII);
373
0
  offset += len;
374
0
  len = tvb_strsize(tvb, offset);
375
0
  proto_tree_add_item(tree, hf_saprouter_error_detail, tvb, offset, len, ENC_ASCII);
376
0
  offset += len;
377
0
  len = tvb_strsize(tvb, offset);
378
0
  proto_tree_add_item(tree, hf_saprouter_error_time, tvb, offset, len, ENC_ASCII);
379
0
  offset += len;
380
0
  len = tvb_strsize(tvb, offset);
381
0
  proto_tree_add_item(tree, hf_saprouter_error_system_call, tvb, offset, len, ENC_ASCII);
382
0
  offset += len;
383
0
  len = tvb_strsize(tvb, offset);
384
0
  proto_tree_add_item(tree, hf_saprouter_error_errorno, tvb, offset, len, ENC_ASCII);
385
0
  offset += len;
386
0
  len = tvb_strsize(tvb, offset);
387
0
  proto_tree_add_item(tree, hf_saprouter_error_errorno_text, tvb, offset, len, ENC_ASCII);
388
0
  offset += len;
389
0
  len = tvb_strsize(tvb, offset);
390
0
  proto_tree_add_item(tree, hf_saprouter_error_error_count, tvb, offset, len, ENC_ASCII);
391
0
  offset += len;
392
0
  len = tvb_strsize(tvb, offset);
393
0
  proto_tree_add_item(tree, hf_saprouter_error_location, tvb, offset, len, ENC_ASCII);
394
0
  offset += len;
395
396
0
  len = tvb_strsize(tvb, offset);
397
0
  proto_tree_add_item(tree, hf_saprouter_error_unknown, tvb, offset, len, ENC_ASCII);
398
0
  offset += len;
399
0
  len = tvb_strsize(tvb, offset);
400
0
  proto_tree_add_item(tree, hf_saprouter_error_unknown, tvb, offset, len, ENC_ASCII);
401
0
  offset += len;
402
0
  len = tvb_strsize(tvb, offset);
403
0
  proto_tree_add_item(tree, hf_saprouter_error_unknown, tvb, offset, len, ENC_ASCII);
404
0
  offset += len;
405
0
  len = tvb_strsize(tvb, offset);
406
0
  proto_tree_add_item(tree, hf_saprouter_error_unknown, tvb, offset, len, ENC_ASCII);
407
0
  offset += len;
408
409
0
  len = tvb_strsize(tvb, offset);
410
0
  proto_tree_add_item(tree, hf_saprouter_error_eyecatcher, tvb, offset, len, ENC_ASCII);
411
0
}
412
413
414
static tvbuff_t*
415
0
dissect_saprouter_snc_frame(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_, uint32_t offset _U_){
416
417
  /* Call the SNC dissector */
418
0
  if (global_saprouter_snc_dissection == true){
419
0
    return dissect_sapsnc_frame(tvb, pinfo, tree, offset);
420
0
  }
421
422
0
  return NULL;
423
0
}
424
425
426
static int
427
dissect_saprouter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
428
0
{
429
0
  tvbuff_t *next_tvb = NULL;
430
0
  uint8_t opcode;
431
0
  uint32_t offset = 0, eyecatcher_length = 0;
432
0
  conversation_t *conversation = NULL;
433
0
  saprouter_session_state *session_state = NULL;
434
0
  proto_item *ti = NULL, *ri = NULL, *ei = NULL, *ci = NULL, *gi = NULL, *admin_password = NULL;
435
0
  proto_tree *saprouter_tree = NULL, *route_tree = NULL, *text_tree = NULL, *clients_tree = NULL;
436
437
  /* Search for a conversation */
438
0
  conversation = find_or_create_conversation(pinfo);
439
0
  session_state = (saprouter_session_state *)conversation_get_proto_data(conversation, proto_saprouter);
440
0
  if (!session_state){
441
0
    session_state = wmem_new(wmem_file_scope(), saprouter_session_state);
442
0
    if (session_state){
443
0
      session_state->route_information = false;
444
0
      session_state->route_requested_in = 0;
445
0
      session_state->route_accepted = false;
446
0
      session_state->route_accepted_in = 0;
447
0
      session_state->route_snc_protected = false;
448
0
      session_state->src_hostname = NULL;
449
0
      session_state->src_port = 0;
450
0
      session_state->src_password = NULL;
451
0
      session_state->dest_hostname = NULL;
452
0
      session_state->dest_port = 0;
453
0
      session_state->dest_password = NULL;
454
0
      conversation_add_proto_data(conversation, proto_saprouter, session_state);
455
0
    } else {
456
      /* Unable to establish a conversation, break dissection of the packet */
457
0
      return 0;
458
0
    }
459
0
  }
460
461
  /* Add the protocol to the column */
462
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "SAPROUTER");
463
464
  /* Add the main SAP Router subtree */
465
0
  ti = proto_tree_add_item(tree, proto_saprouter, tvb, offset, -1, ENC_NA);
466
0
  saprouter_tree = proto_item_add_subtree(ti, ett_saprouter);
467
468
  /* Get the 'eye catcher' length */
469
0
  eyecatcher_length = tvb_strsize(tvb, offset);
470
471
  /* Niping message */
472
0
  if (tvb_reported_length_remaining(tvb, offset) >= 10 && tvb_strneql(tvb, offset, SAPROUTER_TYPE_NIPING_STRING, 10) == 0) {
473
0
    col_set_str(pinfo->cinfo, COL_INFO, "Niping message");
474
475
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, offset, 10, ENC_ASCII);
476
0
    offset += 10;
477
0
    proto_item_append_text(ti, ", Niping message");
478
479
0
    if (tvb_reported_length_remaining(tvb, offset)) {
480
0
      proto_tree_add_item(saprouter_tree, hf_saprouter_niping_message, tvb, offset, -1, ENC_NA);
481
0
    }
482
483
0
  }
484
  /* Admin Message Type */
485
0
  else if (tvb_strneql(tvb, offset, SAPROUTER_TYPE_ADMIN_STRING, eyecatcher_length) == 0) {
486
0
    col_set_str(pinfo->cinfo, COL_INFO, "Admin message");
487
488
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, offset, eyecatcher_length, ENC_ASCII);
489
0
    offset += eyecatcher_length;
490
0
    proto_item_append_text(ti, ", Admin message");
491
492
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_ni_version, tvb, offset, 1, ENC_BIG_ENDIAN);
493
0
    offset++;
494
495
0
    opcode = tvb_get_uint8(tvb, offset);
496
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_admin_command, tvb, offset, 1, ENC_BIG_ENDIAN);
497
0
    offset++;
498
499
0
    switch (opcode){
500
0
      case 2:{  /* Info request */
501
0
        offset+=2; /* Skip 2 bytes */
502
        /* Check if a password was supplied */
503
0
        if (tvb_offset_exists(tvb, offset) && (tvb_strsize(tvb, offset) > 0)){
504
0
          admin_password = proto_tree_add_item(saprouter_tree, hf_saprouter_admin_password, tvb, offset, tvb_strsize(tvb, offset), ENC_ASCII);
505
0
          expert_add_info(pinfo, admin_password, &ei_saprouter_info_password_found);
506
507
          /* Add the password to the credential tap */
508
0
          tap_credential_t *auth =  wmem_new0(pinfo->pool, tap_credential_t);
509
0
          auth->num = pinfo->num;
510
0
          auth->password_hf_id = hf_saprouter_admin_password;
511
0
          auth->proto = "SAP Router Info Request password";
512
0
          auth->username = wmem_strdup(pinfo->pool, TAP_CREDENTIALS_PLACEHOLDER);
513
0
          tap_queue_packet(credentials_tap, pinfo, auth);
514
0
        }
515
0
        break;
516
0
      }
517
0
      case 10:  /* Set Peer Trace */
518
0
      case 11:{ /* Clear Peer Trace */
519
0
        proto_tree_add_item(saprouter_tree, hf_saprouter_admin_address_mask, tvb, offset, 32, ENC_ASCII);
520
0
        break;
521
0
      }
522
0
      case 6:  /* Cancel Route request */
523
0
      case 12: /* Trace Connection */
524
0
      case 13: /* Trace Connection */
525
0
      {
526
0
        uint16_t client_count = 0, client_count_actual = 0;
527
528
        /* Retrieve the client count first */
529
0
        if (opcode == 6){
530
0
          offset+=2; /* Skip 2 bytes for Cancel Route request*/
531
0
          client_count = tvb_get_ntohs(tvb, offset);
532
0
          proto_tree_add_item(saprouter_tree, hf_saprouter_admin_client_count_short, tvb, offset, 2, ENC_BIG_ENDIAN);
533
0
          offset+=2;
534
0
        } else {
535
0
          client_count = tvb_get_ntohl(tvb, offset);
536
0
          proto_tree_add_item(saprouter_tree, hf_saprouter_admin_client_count_int, tvb, offset, 4, ENC_BIG_ENDIAN);
537
0
          offset+=4;
538
0
        }
539
540
        /* Parse the list of client IDs */
541
0
        ci = proto_tree_add_item(saprouter_tree, hf_saprouter_admin_client_ids, tvb, offset, 4*client_count, ENC_NA);
542
0
        clients_tree = proto_item_add_subtree(ci, ett_saprouter);
543
0
        while (tvb_offset_exists(tvb, offset) && tvb_reported_length_remaining(tvb, offset)>=4){
544
0
          proto_tree_add_item(clients_tree, hf_saprouter_admin_client_id, tvb, offset, 4, ENC_BIG_ENDIAN);
545
0
          offset+=4;
546
0
          client_count_actual+=1;
547
0
        }
548
549
        /* Check if the actual count of IDs differes from the reported number */
550
0
        if ((client_count_actual != client_count) || tvb_reported_length_remaining(tvb, offset)>0){
551
0
          expert_add_info(pinfo, clients_tree, &ei_saprouter_invalid_client_ids);
552
0
        }
553
554
0
        break;
555
0
      }
556
0
      default: {
557
        /* Skip 2 bytes */
558
0
        break;
559
0
      }
560
0
    }
561
562
  /* Route Message Type */
563
0
  } else if (tvb_strneql(tvb, offset, SAPROUTER_TYPE_ROUTE_STRING, eyecatcher_length) == 0){
564
0
    uint32_t route_length = 0, route_offset = 0;
565
566
0
    col_set_str(pinfo->cinfo, COL_INFO, "Route message");
567
568
    /* Get the route length/offset */
569
0
    route_length = tvb_get_ntohl(tvb, offset + SAPROUTER_ROUTE_LENGTH_OFFSET);
570
0
    route_offset = offset + SAPROUTER_ROUTE_OFFSET_OFFSET + 4;
571
572
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, 0, eyecatcher_length, ENC_ASCII);
573
0
    offset += eyecatcher_length;
574
0
    proto_item_append_text(ti, ", Route message");
575
    /* Add the fields */
576
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_route_version, tvb, offset, 1, ENC_BIG_ENDIAN);
577
0
    offset++;
578
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_ni_version, tvb, offset, 1, ENC_BIG_ENDIAN);
579
0
    offset++;
580
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_entries, tvb, offset, 1, ENC_BIG_ENDIAN);
581
0
    offset++;
582
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_talk_mode, tvb, offset, 1, ENC_BIG_ENDIAN);
583
0
    offset+=3; /* There're two unused bytes there */
584
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_rest_nodes, tvb, offset, 1, ENC_BIG_ENDIAN);
585
0
    offset++;
586
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_route_length, tvb, offset, 4, ENC_BIG_ENDIAN);
587
0
    offset+=4;
588
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_route_offset, tvb, offset, 4, ENC_BIG_ENDIAN);
589
0
    offset+=4;
590
    /* Add the route tree */
591
0
    if ((uint32_t)tvb_reported_length_remaining(tvb, offset) != route_length){
592
0
      expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_route_invalid_length, "Route string length is invalid (remaining=%d, route_length=%d)", tvb_reported_length_remaining(tvb, offset), route_length);
593
0
      route_length = (uint32_t)tvb_reported_length_remaining(tvb, offset);
594
0
    }
595
0
    ri = proto_tree_add_item(saprouter_tree, hf_saprouter_route, tvb, offset, route_length, ENC_NA);
596
0
    route_tree = proto_item_add_subtree(ri, ett_saprouter);
597
598
    /* Dissect the route string */
599
0
    dissect_routestring(tvb, pinfo, route_tree, route_offset, session_state);
600
601
    /* If this is the first time we're seeing this packet, mark it as the one where the route was requested */
602
0
    if (!pinfo->fd->visited) {
603
0
      session_state->route_requested_in = pinfo->num;
604
0
    }
605
606
    /* Add the route to the colinfo*/
607
0
    if (session_state->src_hostname){
608
0
      col_append_fstr(pinfo->cinfo, COL_INFO, ", Source: Hostname=%s Service Port=%d", session_state->src_hostname, session_state->src_port);
609
0
      if (strlen(session_state->src_password)>0)
610
0
        col_append_fstr(pinfo->cinfo, COL_INFO, " Password=%s", session_state->src_password);
611
0
    }
612
0
    if (session_state->dest_hostname){
613
0
      col_append_fstr(pinfo->cinfo, COL_INFO, ", Destination: Hostname=%s Service Port=%d", session_state->dest_hostname, session_state->dest_port);
614
0
      if (strlen(session_state->dest_password)>0)
615
0
        col_append_fstr(pinfo->cinfo, COL_INFO, " Password=%s", session_state->dest_password);
616
0
    }
617
618
0
    if (session_state->route_accepted && session_state->route_accepted_in) {
619
0
      gi = proto_tree_add_uint(saprouter_tree, hf_saprouter_route_accepted_in, tvb, 0, 0, session_state->route_accepted_in);
620
0
      proto_item_set_generated(gi);
621
0
    }
622
623
  /* Error Information/Control Message Type */
624
0
  } else if (tvb_strneql(tvb, offset, SAPROUTER_TYPE_ERR_STRING, eyecatcher_length) == 0){
625
626
    /* Extract the opcode if possible to determine the type of message */
627
0
    if (tvb_offset_exists(tvb, offset + 10)) {
628
0
      opcode = tvb_get_uint8(tvb, offset + 10);
629
0
    } else {
630
0
      opcode = 0;
631
0
    }
632
633
0
    col_set_str(pinfo->cinfo, COL_INFO, (opcode==0)? "Error information" : "Control message");
634
635
0
    uint32_t text_length = 0;
636
637
0
    proto_item_append_text(ti, (opcode==0)? ", Error information" : ", Control message");
638
    /* Add the fields */
639
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, offset, eyecatcher_length, ENC_ASCII);
640
0
    offset += eyecatcher_length;
641
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_ni_version, tvb, offset, 1, ENC_BIG_ENDIAN);
642
0
    offset++;
643
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_opcode, tvb, offset, 1, ENC_BIG_ENDIAN);
644
0
    offset+=2; /* There's a unused byte there */
645
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_return_code, tvb, offset, 4, ENC_BIG_ENDIAN);
646
0
    offset+=4;
647
648
0
    text_length = tvb_get_ntohl(tvb, offset);
649
    /* Error Information Message */
650
0
    if (opcode == 0){
651
0
      proto_tree_add_item(saprouter_tree, hf_saprouter_error_length, tvb, offset, 4, ENC_BIG_ENDIAN);
652
0
      offset+=4;
653
0
      if ((text_length > 0) && tvb_offset_exists(tvb, offset+text_length)){
654
        /* Add the error string tree */
655
0
        ei = proto_tree_add_item(saprouter_tree, hf_saprouter_error_string, tvb, offset, text_length, ENC_NA);
656
0
        text_tree = proto_item_add_subtree(ei, ett_saprouter);
657
0
        dissect_errorstring(tvb, text_tree, offset);
658
0
        offset += text_length;
659
0
      }
660
661
      /* Add an unknown int field */
662
0
      proto_tree_add_item(saprouter_tree, hf_saprouter_unknown, tvb, offset, 4, ENC_BIG_ENDIAN);
663
664
    /* Control Message */
665
0
    } else {
666
      /* Add the opcode name */
667
0
            proto_item_append_text(ti, ", opcode=%s", val_to_str_const(opcode, saprouter_opcode_vals, "Unknown"));
668
0
      col_append_fstr(pinfo->cinfo, COL_INFO, ", opcode=%s", val_to_str_const(opcode, saprouter_opcode_vals, "Unknown"));
669
670
0
      proto_tree_add_item(saprouter_tree, hf_saprouter_control_length, tvb, offset, 4, ENC_BIG_ENDIAN);
671
0
      offset+=4;
672
0
      if ((text_length >0) && tvb_offset_exists(tvb, offset+text_length)){
673
        /* Add the control string tree */
674
0
        proto_tree_add_item(saprouter_tree, hf_saprouter_control_string, tvb, offset, text_length, ENC_ASCII);
675
0
        offset += text_length;
676
0
      }
677
678
      /* SNC request, mark the conversation as SNC protected and dissect the SNC frame */
679
0
      if (opcode == 70 || opcode == 71){
680
0
        session_state->route_snc_protected = true;
681
0
        dissect_saprouter_snc_frame(tvb, pinfo, tree, offset);
682
683
      /* Other opcodes */
684
0
      } else {
685
0
        proto_tree_add_item(saprouter_tree, hf_saprouter_control_unknown, tvb, offset, 4, ENC_ASCII);
686
0
      }
687
688
0
    }
689
690
  /* Route Acceptance (NI_PONG) Message Type */
691
0
  } else if (tvb_strneql(tvb, offset, SAPROUTER_TYPE_ROUTE_ACCEPT, eyecatcher_length) == 0){
692
    /* Route information available */
693
0
    if (session_state->route_information){
694
      /* If this is the first time we're seen the packet, mark is as the one where the route was accepted */
695
0
      if (!pinfo->fd->visited) {
696
0
        session_state->route_accepted = true;
697
0
        session_state->route_accepted_in = pinfo->num;
698
0
      }
699
700
0
      col_append_fstr(pinfo->cinfo, COL_INFO, ", from %s:%d to %s:%d", session_state->src_hostname, session_state->src_port, session_state->dest_hostname, session_state->dest_port);
701
0
      proto_item_append_text(ti, ", from %s:%d to %s:%d", session_state->src_hostname, session_state->src_port, session_state->dest_hostname, session_state->dest_port);
702
703
0
      if (session_state->route_requested_in) {
704
0
        gi = proto_tree_add_uint(saprouter_tree, hf_saprouter_route_requested_in, tvb, 0, 0, session_state->route_requested_in);
705
0
        proto_item_set_generated(gi);
706
0
      }
707
0
    }
708
709
  /* Unknown Message Type */
710
0
  } else {
711
712
0
    col_set_str(pinfo->cinfo, COL_INFO, "Routed message");
713
0
    proto_item_append_text(ti, ", Routed message");
714
715
    /* If the session is protected with SNC, first dissect the SNC frame
716
     * and save the content for further dissection.
717
     */
718
0
    if (session_state->route_snc_protected) {
719
0
      col_append_str(pinfo->cinfo, COL_INFO, ", SNC protected");
720
0
      proto_item_append_text(ti, ", SNC protected");
721
0
      next_tvb = dissect_saprouter_snc_frame(tvb, pinfo, tree, offset);
722
723
    /* If the session is not protected dissect the entire payload */
724
0
    } else {
725
0
      next_tvb = tvb;
726
0
    }
727
728
    /* If the session has information about the route requested */
729
0
    if (session_state->route_information){
730
731
      /* Route accepted */
732
0
      if (session_state->route_accepted){
733
734
0
        col_append_fstr(pinfo->cinfo, COL_INFO, ", from %s:%d to %s:%d ", session_state->src_hostname, session_state->src_port, session_state->dest_hostname, session_state->dest_port);
735
0
        proto_item_append_text(ti, ", from %s:%d to %s:%d ", session_state->src_hostname, session_state->src_port, session_state->dest_hostname, session_state->dest_port);
736
737
0
        if (session_state->route_requested_in) {
738
0
          gi = proto_tree_add_uint(saprouter_tree, hf_saprouter_route_requested_in, tvb, 0, 0, session_state->route_requested_in);
739
0
          proto_item_set_generated(gi);
740
0
        }
741
0
        if (session_state->route_accepted_in) {
742
0
          gi = proto_tree_add_uint(saprouter_tree, hf_saprouter_route_accepted_in, tvb, 0, 0, session_state->route_accepted_in);
743
0
          proto_item_set_generated(gi);
744
0
        }
745
746
      /* Route not accepted but some information available */
747
0
      } else {
748
0
        col_append_str(pinfo->cinfo, COL_INFO, ", to unknown destination");
749
0
        proto_item_append_text(ti, ", to unknown destination");
750
0
      }
751
752
      /* Call the dissector in the NI protocol sub-dissectors table
753
       * according to the route destination port number. */
754
0
      if (next_tvb) {
755
0
        dissect_sap_protocol_payload(next_tvb, offset, pinfo, tree, 0, session_state->dest_port);
756
0
      }
757
758
0
    } else {
759
      /* No route information available */
760
0
      col_append_str(pinfo->cinfo, COL_INFO, ", to unknown destination");
761
0
      proto_item_append_text(ti, ", to unknown destination");
762
0
    }
763
0
  }
764
765
0
  return tvb_reported_length(tvb);
766
0
}
767
768
void
769
proto_register_saprouter(void)
770
14
{
771
14
  static hf_register_info hf[] = {
772
14
    { &hf_saprouter_type,
773
14
      { "Type", "saprouter.type", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
774
775
    /* Niping message */
776
14
    { &hf_saprouter_niping_message,
777
14
      { "Niping message", "saprouter.message", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
778
779
    /* NI Route messages */
780
14
    { &hf_saprouter_route_version,
781
14
      { "Route version", "saprouter.version", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
782
14
    { &hf_saprouter_ni_version,
783
14
      { "NI version", "saprouter.niversion", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
784
14
    { &hf_saprouter_entries,
785
14
      { "Entries", "saprouter.entries", FT_UINT8, BASE_DEC, NULL, 0x0, "Total number of entries", HFILL }},
786
14
    { &hf_saprouter_talk_mode,
787
14
      { "Talk Mode", "saprouter.talkmode", FT_UINT8, BASE_DEC, VALS(saprouter_talk_mode_vals), 0x0, NULL, HFILL }},
788
14
    { &hf_saprouter_rest_nodes,
789
14
      { "Remaining Hops", "saprouter.restnodes", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
790
14
    { &hf_saprouter_route_length,
791
14
      { "Route String Length", "saprouter.routelength", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
792
14
    { &hf_saprouter_route_offset,
793
14
      { "Route String Offset", "saprouter.routeoffset", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
794
14
    { &hf_saprouter_route,
795
14
      { "Route String", "saprouter.routestring", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
796
14
    { &hf_saprouter_route_string,
797
14
      { "Route Hop", "saprouter.routestring", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
798
14
    { &hf_saprouter_route_string_hostname,
799
14
      { "Hostname", "saprouter.routestring.hostname", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
800
14
    { &hf_saprouter_route_string_service,
801
14
      { "Service", "saprouter.routestring.service", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
802
14
    { &hf_saprouter_route_string_password,
803
14
      { "Password", "saprouter.routestring.password", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
804
805
14
    { &hf_saprouter_route_requested_in,
806
14
      { "Route Requested in", "saprouter.requested_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "The route request for this packet is in this packet", HFILL }},
807
14
    { &hf_saprouter_route_accepted_in,
808
14
      { "Route Accepted in", "saprouter.accepted_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "The route for this packet was accepted in this packet", HFILL }},
809
810
    /* NI error information / Control messages */
811
14
    { &hf_saprouter_opcode,
812
14
      { "Operation Code", "saprouter.opcode", FT_UINT8, BASE_DEC, VALS(saprouter_opcode_vals), 0x0, NULL, HFILL }},
813
14
    { &hf_saprouter_return_code,
814
14
      { "Return Code", "saprouter.returncode", FT_INT32, BASE_DEC, VALS(saprouter_return_code_vals), 0x0, NULL, HFILL }},
815
14
    { &hf_saprouter_unknown,
816
14
      { "Unknown field", "saprouter.unknown", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
817
818
    /* NI Error Information messages */
819
14
    { &hf_saprouter_error_length,
820
14
      { "Error Information Text Length", "saprouter.errorlength", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
821
14
    { &hf_saprouter_error_string,
822
14
      { "Error Information Text", "saprouter.errortext", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
823
14
    { &hf_saprouter_error_eyecatcher,
824
14
      { "Eyecatcher", "saprouter.errortext.eyecatcher", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
825
14
    { &hf_saprouter_error_counter,
826
14
      { "Counter", "saprouter.errortext.counter", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
827
14
    { &hf_saprouter_error_error,
828
14
      { "Error", "saprouter.errortext.error", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
829
14
    { &hf_saprouter_error_return_code,
830
14
      { "Return code", "saprouter.errortext.returncode", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
831
14
    { &hf_saprouter_error_component,
832
14
      { "Component", "saprouter.errortext.component", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
833
14
    { &hf_saprouter_error_release,
834
14
      { "Release", "saprouter.errortext.release", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
835
14
    { &hf_saprouter_error_version,
836
14
      { "Version", "saprouter.errortext.version", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
837
14
    { &hf_saprouter_error_module,
838
14
      { "Module", "saprouter.errortext.module", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
839
14
    { &hf_saprouter_error_line,
840
14
      { "Line", "saprouter.errortext.line", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
841
14
    { &hf_saprouter_error_detail,
842
14
      { "Detail", "saprouter.errortext.detail", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
843
14
    { &hf_saprouter_error_time,
844
14
      { "Time", "saprouter.errortext.time", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
845
14
    { &hf_saprouter_error_system_call,
846
14
      { "System Call", "saprouter.errortext.system_call", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
847
14
    { &hf_saprouter_error_errorno,
848
14
      { "Error Number", "saprouter.errortext.errorno", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
849
14
    { &hf_saprouter_error_errorno_text,
850
14
      { "Error Number Text", "saprouter.errortext.errorno_text", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
851
14
    { &hf_saprouter_error_location,
852
14
      { "Location", "saprouter.errortext.location", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
853
14
    { &hf_saprouter_error_error_count,
854
14
      { "Error Count", "saprouter.errortext.error_count", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
855
14
    { &hf_saprouter_error_unknown,
856
14
      { "Unknown field", "saprouter.errortext.unknown", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
857
858
    /* Control messages */
859
14
    { &hf_saprouter_control_length,
860
14
      { "Control Text Length", "saprouter.controllength", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
861
14
    { &hf_saprouter_control_string,
862
14
      { "Control Text", "saprouter.controltext", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
863
14
    { &hf_saprouter_control_unknown,
864
14
      { "Control Unknown field", "saprouter.controlunknown", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
865
866
    /* Router Admin messages */
867
14
    { &hf_saprouter_admin_command,
868
14
      { "Admin Command", "saprouter.command", FT_UINT8, BASE_DEC, VALS(saprouter_admin_command_vals), 0x0, NULL, HFILL }},
869
14
    { &hf_saprouter_admin_password,
870
14
      { "Admin Command Info Password", "saprouter.password", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
871
14
    { &hf_saprouter_admin_client_count_short,
872
14
      { "Admin Command Client Count", "saprouter.client_count", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
873
14
    { &hf_saprouter_admin_client_count_int,
874
14
      { "Admin Command Client Count", "saprouter.client_count", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
875
14
    { &hf_saprouter_admin_client_ids,
876
14
      { "Admin Command Client IDs", "saprouter.client_ids", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
877
14
    { &hf_saprouter_admin_client_id,
878
14
      { "Admin Command Client ID", "saprouter.client_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
879
14
    { &hf_saprouter_admin_address_mask,
880
14
      { "Admin Command Address Mask", "saprouter.address_mask", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
881
14
  };
882
883
  /* Setup protocol subtree array */
884
14
  static int *ett[] = {
885
14
    &ett_saprouter
886
14
  };
887
888
  /* Register the expert info */
889
14
  static ei_register_info ei[] = {
890
14
    { &ei_saprouter_route_password_found, { "saprouter.routestring.password.found", PI_SECURITY, PI_WARN, "Route password found", EXPFILL }},
891
14
    { &ei_saprouter_info_password_found, { "saprouter.password.found", PI_SECURITY, PI_WARN, "Info password found", EXPFILL }},
892
14
    { &ei_saprouter_route_invalid_length, { "saprouter.routestring.routelength.invalid", PI_MALFORMED, PI_WARN, "The route string length is invalid", EXPFILL }},
893
14
    { &ei_saprouter_invalid_client_ids, { "saprouter.client_ids.invalid", PI_MALFORMED, PI_WARN, "Client IDs list is malformed", EXPFILL }},
894
14
  };
895
896
14
  module_t *saprouter_module;
897
14
  expert_module_t* saprouter_expert;
898
899
  /* Register the protocol */
900
14
  proto_saprouter = proto_register_protocol("SAP Router Protocol", "SAPROUTER", "saprouter");
901
902
14
  proto_register_field_array(proto_saprouter, hf, array_length(hf));
903
14
  proto_register_subtree_array(ett, array_length(ett));
904
905
14
  saprouter_expert = expert_register_protocol(proto_saprouter);
906
14
  expert_register_field_array(saprouter_expert, ei, array_length(ei));
907
908
14
  register_dissector("saprouter", dissect_saprouter, proto_saprouter);
909
910
  /* Register the preferences */
911
14
  saprouter_module = prefs_register_protocol(proto_saprouter, proto_reg_handoff_saprouter);
912
913
14
  range_convert_str(wmem_epan_scope(), &global_saprouter_port_range, SAPROUTER_PORT_RANGE, MAX_TCP_PORT);
914
14
  prefs_register_range_preference(saprouter_module, "tcp_ports", "SAP Router Protocol TCP port numbers", "Port numbers used for SAP Router Protocol (default " SAPROUTER_PORT_RANGE ")", &global_saprouter_port_range, MAX_TCP_PORT);
915
916
14
  prefs_register_bool_preference(saprouter_module, "snc_dissection", "Dissect SAP SNC frames", "Whether the SAP Router Protocol dissector should call the SAP SNC dissector for SNC frames", &global_saprouter_snc_dissection);
917
918
  /* Register the tap*/
919
14
  credentials_tap = register_tap("credentials");
920
921
14
}
922
923
924
/**
925
 * Helpers for dealing with the port range
926
 */
927
static void range_delete_callback (uint32_t port, void *ptr _U_)
928
0
{
929
0
  dissector_delete_uint("sapni.port", port, saprouter_handle);
930
0
}
931
932
static void range_add_callback (uint32_t port, void *ptr _U_)
933
28
{
934
28
  dissector_add_uint("sapni.port", port, saprouter_handle);
935
28
}
936
937
938
/**
939
 * Register Hand off for the SAP Router Protocol
940
 */
941
void
942
proto_reg_handoff_saprouter(void)
943
14
{
944
14
  static bool initialized = false;
945
14
  static range_t *saprouter_port_range;
946
947
14
  if (!initialized) {
948
14
    saprouter_handle = create_dissector_handle(dissect_saprouter, proto_saprouter);
949
14
    initialized = true;
950
14
  } else {
951
0
    range_foreach(saprouter_port_range, range_delete_callback, NULL);
952
0
    wmem_free(wmem_epan_scope(), saprouter_port_range);
953
0
  }
954
955
14
  saprouter_port_range = range_copy(wmem_epan_scope(), global_saprouter_port_range);
956
14
  range_foreach(saprouter_port_range, range_add_callback, NULL);
957
958
14
}
959
960
/*
961
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
962
 *
963
 * Local variables:
964
 * c-basic-offset: 8
965
 * tab-width: 8
966
 * indent-tabs-mode: t
967
 * End:
968
 *
969
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
970
 * :indentSize=8:tabSize=8:noTabs=false:
971
 */