Coverage Report

Created: 2026-09-28 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
#include <epan/credentials.h>
28
#include <epan/tap.h>
29
30
#include "packet-sapni.h"
31
#include "packet-sapsnc.h"
32
33
34
/* Define default ports */
35
16
#define SAPROUTER_PORT_RANGE "3298-3299"
36
37
/*
38
 * Length of the frame header
39
 */
40
#define SAPROUTER_HEADER_LEN  8
41
42
/*
43
 * Offsets of header fields
44
 */
45
0
#define SAPROUTER_ROUTE_LENGTH_OFFSET 16
46
0
#define SAPROUTER_ROUTE_OFFSET_OFFSET 20
47
48
/* SAP Router Eye Catcher strings */
49
0
#define SAPROUTER_TYPE_NIPING_STRING "EYECATCHER"
50
0
#define SAPROUTER_TYPE_ROUTE_STRING "NI_ROUTE"
51
0
#define SAPROUTER_TYPE_ROUTE_ACCEPT "NI_PONG"
52
0
#define SAPROUTER_TYPE_ERR_STRING "NI_RTERR"
53
0
#define SAPROUTER_TYPE_ADMIN_STRING "ROUTER_ADM"
54
0
#define SAPROUTER_ERR_FIXED_LEN   12U
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
static expert_field ei_saprouter_control_invalid_length;
218
219
/* Global port preference */
220
static range_t *global_saprouter_port_range;
221
222
223
/* Global SNC dissection preference */
224
static bool global_saprouter_snc_dissection = true;
225
226
/* Protocol handle */
227
static dissector_handle_t saprouter_handle;
228
229
/* Session state information being tracked in a SAP Router conversation */
230
typedef struct saprouter_session_state {
231
  bool route_information;
232
  unsigned   route_requested_in;
233
  bool route_accepted;
234
  unsigned   route_accepted_in;
235
  bool route_snc_protected;
236
  char  *src_hostname;      /* Source hostname (first entry in the route string) */
237
  uint32_t src_port;        /* Source port number */
238
  char  *src_password;      /* Source password XXX: Check if possible */
239
  char  *dest_hostname;     /* Destination hostname (last entry in the route string) */
240
  uint32_t dest_port;       /* Destination port number */
241
  char  *dest_password;     /* Destination password */
242
} saprouter_session_state;
243
244
/*
245
 *
246
 */
247
void proto_reg_handoff_saprouter(void);
248
void proto_register_saprouter(void);
249
250
251
static uint32_t
252
0
dissect_serviceport(char *port){
253
0
  uint32_t portnumber = 0;
254
255
0
  if (g_ascii_isdigit(port[0])){
256
0
    portnumber = (uint32_t)strtoul(port, NULL, 10);
257
0
  } else if ((strlen(port)>5) && g_str_has_prefix(port, "sapdp")){
258
0
    portnumber = 3200 + (uint32_t)strtoul(port+5, NULL, 10);
259
0
  } else if ((strlen(port)>5) && g_str_has_prefix(port, "sapgw")){
260
0
    portnumber = 3300 + (uint32_t)strtoul(port+5, NULL, 10);
261
0
  } else if ((strlen(port)>5) && g_str_has_prefix(port, "sapms")){
262
0
    portnumber = 3600 + (uint32_t)strtoul(port+5, NULL, 10);
263
0
  }
264
0
  return (portnumber);
265
0
}
266
267
static bool
268
saprouter_tvb_strsize_bounded(tvbuff_t *tvb, uint32_t offset, uint32_t *len)
269
0
{
270
0
  unsigned nul_offset;
271
0
  int remaining;
272
273
0
  remaining = tvb_captured_length_remaining(tvb, offset);
274
0
  if (remaining <= 0) {
275
0
    return false;
276
0
  }
277
278
0
  if (!tvb_find_uint8_length(tvb, offset, (unsigned)remaining, '\0', &nul_offset)) {
279
0
    return false;
280
0
  }
281
282
0
  *len = nul_offset - offset + 1;
283
0
  return true;
284
0
}
285
286
static bool
287
saprouter_type_matches(tvbuff_t *tvb, uint32_t offset, uint32_t eyecatcher_length, const char *type)
288
0
{
289
0
  uint32_t type_length = (uint32_t)strlen(type);
290
291
0
  if (eyecatcher_length != type_length + 1) {
292
0
    return false;
293
0
  }
294
295
0
  return tvb_strneql(tvb, offset, type, type_length) == 0 &&
296
0
      tvb_get_uint8(tvb, offset + type_length) == '\0';
297
0
}
298
299
static void
300
0
dissect_routestring(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, uint32_t offset, saprouter_session_state *session_state){
301
0
  int hop = 1;
302
0
  uint32_t len, route_offset, int_port = 0;
303
0
  char *hostname = NULL, *port = NULL, *password = NULL;
304
0
  proto_item *route_hop = NULL, *route_password = NULL;
305
0
  proto_tree *route_hop_tree = NULL;
306
307
0
  while (tvb_offset_exists(tvb, offset)){
308
0
    route_offset = offset; hostname = port = password = NULL;
309
310
    /* Create the subtree for this route hop */
311
0
    route_hop = proto_tree_add_item(tree, hf_saprouter_route_string, tvb, offset, 0, ENC_NA);
312
0
    route_hop_tree = proto_item_add_subtree(route_hop, ett_saprouter);
313
0
    proto_item_append_text(route_hop, ", nro %d", hop);
314
315
    /* Dissect the hostname string */
316
0
    if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) {
317
0
      break;
318
0
    }
319
0
    hostname = (char *)tvb_get_string_enc(wmem_file_scope(), tvb, offset, len - 1, ENC_ASCII);
320
0
    proto_tree_add_item(route_hop_tree, hf_saprouter_route_string_hostname, tvb, offset, len, ENC_ASCII);
321
0
    offset += len;
322
323
    /* Dissect the port string */
324
0
    if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) {
325
0
      break;
326
0
    }
327
0
    port = (char *)tvb_get_string_enc(pinfo->pool, tvb, offset, len - 1, ENC_ASCII);
328
0
    proto_tree_add_item(route_hop_tree, hf_saprouter_route_string_service, tvb, offset, len, ENC_ASCII);
329
0
    offset += len;
330
331
    /* Dissect the password string */
332
0
    if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) {
333
0
      break;
334
0
    }
335
0
    password = (char *)tvb_get_string_enc(wmem_file_scope(), tvb, offset, len - 1, ENC_ASCII);
336
0
    route_password = proto_tree_add_item(route_hop_tree, hf_saprouter_route_string_password, tvb, offset, len, ENC_ASCII);
337
338
    /* If a password was found, add a expert warning in the security category */
339
0
    if (len > 1){
340
0
      expert_add_info(pinfo, route_password, &ei_saprouter_route_password_found);
341
342
      /* Add the password to the credential tap */
343
0
      tap_credential_t *auth =  wmem_new0(pinfo->pool, tap_credential_t);
344
0
      auth->num = pinfo->num;
345
0
      auth->password_hf_id = hf_saprouter_route_string_password;
346
0
      auth->proto = "SAP Router Route String password";
347
0
      auth->username = wmem_strdup(pinfo->pool, CREDENTIALS_PLACEHOLDER);
348
0
      tap_queue_packet(credentials_tap, pinfo, auth);
349
0
    }
350
0
    offset += len;
351
352
    /* Adjust the size of the route hop item now that we know the size */
353
0
    proto_item_set_len(route_hop, offset - route_offset);
354
355
    /* Get the service port in numeric format */
356
0
    int_port = dissect_serviceport(port);
357
358
    /* Add the first hostname/port as source in the conversation state*/
359
0
    if ((hop==1) && !(pinfo->fd->visited)){
360
0
      session_state->src_hostname = hostname;
361
0
      session_state->src_port = int_port;
362
0
      session_state->src_password = password;
363
0
    }
364
0
    hop++;
365
0
  }
366
367
0
  if (!(pinfo->fd->visited)) {
368
    /* Add the last hostname/port as destination */
369
0
    if (hop!=1){
370
0
      session_state->dest_hostname = hostname;
371
0
      session_state->dest_port = int_port;
372
0
      session_state->dest_password = password;
373
0
    }
374
    /* Save the status of the conversation state */
375
0
    session_state->route_information = true;
376
0
    session_state->route_accepted = false;
377
0
  }
378
379
0
}
380
381
static void
382
dissect_errorstring(tvbuff_t *tvb, proto_tree *tree, uint32_t offset)
383
0
{
384
0
  uint32_t len;
385
386
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
387
0
  proto_tree_add_item(tree, hf_saprouter_error_eyecatcher, tvb, offset, len, ENC_ASCII);
388
0
  offset += len;
389
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
390
0
  proto_tree_add_item(tree, hf_saprouter_error_counter, tvb, offset, len, ENC_ASCII);
391
0
  offset += len;
392
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
393
0
  proto_tree_add_item(tree, hf_saprouter_error_error, tvb, offset, len, ENC_ASCII);
394
0
  offset += len;
395
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
396
0
  proto_tree_add_item(tree, hf_saprouter_error_return_code, tvb, offset, len, ENC_ASCII);
397
0
  offset += len;
398
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
399
0
  proto_tree_add_item(tree, hf_saprouter_error_component, tvb, offset, len, ENC_ASCII);
400
0
  offset += len;
401
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
402
0
  proto_tree_add_item(tree, hf_saprouter_error_release, tvb, offset, len, ENC_ASCII);
403
0
  offset += len;
404
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
405
0
  proto_tree_add_item(tree, hf_saprouter_error_version, tvb, offset, len, ENC_ASCII);
406
0
  offset += len;
407
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
408
0
  proto_tree_add_item(tree, hf_saprouter_error_module, tvb, offset, len, ENC_ASCII);
409
0
  offset += len;
410
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
411
0
  proto_tree_add_item(tree, hf_saprouter_error_line, tvb, offset, len, ENC_ASCII);
412
0
  offset += len;
413
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
414
0
  proto_tree_add_item(tree, hf_saprouter_error_detail, tvb, offset, len, ENC_ASCII);
415
0
  offset += len;
416
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
417
0
  proto_tree_add_item(tree, hf_saprouter_error_time, tvb, offset, len, ENC_ASCII);
418
0
  offset += len;
419
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
420
0
  proto_tree_add_item(tree, hf_saprouter_error_system_call, tvb, offset, len, ENC_ASCII);
421
0
  offset += len;
422
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
423
0
  proto_tree_add_item(tree, hf_saprouter_error_errorno, tvb, offset, len, ENC_ASCII);
424
0
  offset += len;
425
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
426
0
  proto_tree_add_item(tree, hf_saprouter_error_errorno_text, tvb, offset, len, ENC_ASCII);
427
0
  offset += len;
428
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
429
0
  proto_tree_add_item(tree, hf_saprouter_error_error_count, tvb, offset, len, ENC_ASCII);
430
0
  offset += len;
431
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
432
0
  proto_tree_add_item(tree, hf_saprouter_error_location, tvb, offset, len, ENC_ASCII);
433
0
  offset += len;
434
435
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
436
0
  proto_tree_add_item(tree, hf_saprouter_error_unknown, tvb, offset, len, ENC_ASCII);
437
0
  offset += len;
438
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
439
0
  proto_tree_add_item(tree, hf_saprouter_error_unknown, tvb, offset, len, ENC_ASCII);
440
0
  offset += len;
441
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
442
0
  proto_tree_add_item(tree, hf_saprouter_error_unknown, tvb, offset, len, ENC_ASCII);
443
0
  offset += len;
444
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
445
0
  proto_tree_add_item(tree, hf_saprouter_error_unknown, tvb, offset, len, ENC_ASCII);
446
0
  offset += len;
447
448
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &len)) return;
449
0
  proto_tree_add_item(tree, hf_saprouter_error_eyecatcher, tvb, offset, len, ENC_ASCII);
450
0
}
451
452
453
static tvbuff_t*
454
0
dissect_saprouter_snc_frame(tvbuff_t *tvb _U_, packet_info *pinfo _U_, proto_tree *tree _U_, uint32_t offset _U_){
455
456
  /* Call the SNC dissector */
457
0
  if (global_saprouter_snc_dissection == true){
458
0
    return dissect_sapsnc_frame(tvb, pinfo, tree, offset);
459
0
  }
460
461
0
  return NULL;
462
0
}
463
464
465
static int
466
dissect_saprouter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
467
0
{
468
0
  tvbuff_t *next_tvb = NULL;
469
0
  uint8_t opcode;
470
0
  uint32_t offset = 0, eyecatcher_length = 0;
471
0
  int remaining;
472
0
  conversation_t *conversation = NULL;
473
0
  saprouter_session_state *session_state = NULL;
474
0
  proto_item *ti = NULL, *ri = NULL, *ei = NULL, *ci = NULL, *gi = NULL, *admin_password = NULL;
475
0
  proto_tree *saprouter_tree = NULL, *route_tree = NULL, *text_tree = NULL, *clients_tree = NULL;
476
477
  /* Search for a conversation */
478
0
  conversation = find_or_create_conversation(pinfo);
479
0
  session_state = (saprouter_session_state *)conversation_get_proto_data(conversation, proto_saprouter);
480
0
  if (!session_state){
481
0
    session_state = wmem_new(wmem_file_scope(), saprouter_session_state);
482
0
    if (session_state){
483
0
      session_state->route_information = false;
484
0
      session_state->route_requested_in = 0;
485
0
      session_state->route_accepted = false;
486
0
      session_state->route_accepted_in = 0;
487
0
      session_state->route_snc_protected = false;
488
0
      session_state->src_hostname = NULL;
489
0
      session_state->src_port = 0;
490
0
      session_state->src_password = NULL;
491
0
      session_state->dest_hostname = NULL;
492
0
      session_state->dest_port = 0;
493
0
      session_state->dest_password = NULL;
494
0
      conversation_add_proto_data(conversation, proto_saprouter, session_state);
495
0
    } else {
496
      /* Unable to establish a conversation, break dissection of the packet */
497
0
      return 0;
498
0
    }
499
0
  }
500
501
  /* Add the protocol to the column */
502
0
  col_set_str(pinfo->cinfo, COL_PROTOCOL, "SAPROUTER");
503
504
  /* Add the main SAP Router subtree */
505
0
  ti = proto_tree_add_item(tree, proto_saprouter, tvb, offset, -1, ENC_NA);
506
0
  saprouter_tree = proto_item_add_subtree(ti, ett_saprouter);
507
508
  /* Get the 'eye catcher' length */
509
0
  if (!saprouter_tvb_strsize_bounded(tvb, offset, &eyecatcher_length)) {
510
0
    remaining = tvb_reported_length_remaining(tvb, offset);
511
0
    eyecatcher_length = remaining > 0 ? (uint32_t)remaining : 0;
512
0
  }
513
514
  /* Niping message */
515
0
  if (tvb_reported_length_remaining(tvb, offset) >= 10 && tvb_strneql(tvb, offset, SAPROUTER_TYPE_NIPING_STRING, 10) == 0) {
516
0
    col_set_str(pinfo->cinfo, COL_INFO, "Niping message");
517
518
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, offset, 10, ENC_ASCII);
519
0
    offset += 10;
520
0
    proto_item_append_text(ti, ", Niping message");
521
522
0
    if (tvb_reported_length_remaining(tvb, offset)) {
523
0
      proto_tree_add_item(saprouter_tree, hf_saprouter_niping_message, tvb, offset, -1, ENC_NA);
524
0
    }
525
526
0
  }
527
  /* Admin Message Type */
528
0
  else if (saprouter_type_matches(tvb, offset, eyecatcher_length, SAPROUTER_TYPE_ADMIN_STRING)) {
529
0
    col_set_str(pinfo->cinfo, COL_INFO, "Admin message");
530
531
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, offset, eyecatcher_length, ENC_ASCII);
532
0
    offset += eyecatcher_length;
533
0
    proto_item_append_text(ti, ", Admin message");
534
535
0
    if (tvb_reported_length_remaining(tvb, offset) < 2) {
536
0
      expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_control_invalid_length, "SAP Router admin message is shorter than 2 fixed bytes");
537
0
      return tvb_reported_length(tvb);
538
0
    }
539
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_ni_version, tvb, offset, 1, ENC_BIG_ENDIAN);
540
0
    offset++;
541
542
0
    opcode = tvb_get_uint8(tvb, offset);
543
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_admin_command, tvb, offset, 1, ENC_BIG_ENDIAN);
544
0
    offset++;
545
546
0
    switch (opcode){
547
0
      case 2:{  /* Info request */
548
0
        uint32_t password_len;
549
550
0
        if (tvb_reported_length_remaining(tvb, offset) < 2) {
551
0
          expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_control_invalid_length, "SAP Router admin info request is shorter than 2 fixed bytes");
552
0
          return tvb_reported_length(tvb);
553
0
        }
554
0
        offset+=2; /* Skip 2 bytes */
555
        /* Check if a password was supplied */
556
0
        if (saprouter_tvb_strsize_bounded(tvb, offset, &password_len) && password_len > 1){
557
0
          admin_password = proto_tree_add_item(saprouter_tree, hf_saprouter_admin_password, tvb, offset, password_len, ENC_ASCII);
558
0
          expert_add_info(pinfo, admin_password, &ei_saprouter_info_password_found);
559
560
          /* Add the password to the credential tap */
561
0
          tap_credential_t *auth =  wmem_new0(pinfo->pool, tap_credential_t);
562
0
          auth->num = pinfo->num;
563
0
          auth->password_hf_id = hf_saprouter_admin_password;
564
0
          auth->proto = "SAP Router Info Request password";
565
0
          auth->username = wmem_strdup(pinfo->pool, CREDENTIALS_PLACEHOLDER);
566
0
          tap_queue_packet(credentials_tap, pinfo, auth);
567
0
        }
568
0
        break;
569
0
      }
570
0
      case 10:  /* Set Peer Trace */
571
0
      case 11:{ /* Clear Peer Trace */
572
0
        proto_tree_add_item(saprouter_tree, hf_saprouter_admin_address_mask, tvb, offset, 32, ENC_ASCII);
573
0
        break;
574
0
      }
575
0
      case 6:  /* Cancel Route request */
576
0
      case 12: /* Trace Connection */
577
0
      case 13: /* Trace Connection */
578
0
      {
579
0
        uint32_t client_count = 0, client_count_actual = 0;
580
581
        /* Retrieve the client count first */
582
0
        if (opcode == 6){
583
0
          if (tvb_reported_length_remaining(tvb, offset) < 4) {
584
0
            expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_control_invalid_length, "SAP Router cancel route request is shorter than 4 fixed bytes");
585
0
            return tvb_reported_length(tvb);
586
0
          }
587
0
          offset+=2; /* Skip 2 bytes for Cancel Route request*/
588
0
          client_count = tvb_get_ntohs(tvb, offset);
589
0
          proto_tree_add_item(saprouter_tree, hf_saprouter_admin_client_count_short, tvb, offset, 2, ENC_BIG_ENDIAN);
590
0
          offset+=2;
591
0
        } else {
592
0
          if (tvb_reported_length_remaining(tvb, offset) < 4) {
593
0
            expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_control_invalid_length, "SAP Router trace connection request is shorter than 4 fixed bytes");
594
0
            return tvb_reported_length(tvb);
595
0
          }
596
0
          client_count = tvb_get_ntohl(tvb, offset);
597
0
          proto_tree_add_item(saprouter_tree, hf_saprouter_admin_client_count_int, tvb, offset, 4, ENC_BIG_ENDIAN);
598
0
          offset+=4;
599
0
        }
600
601
        /* Parse the list of client IDs */
602
0
        remaining = tvb_reported_length_remaining(tvb, offset);
603
0
        ci = proto_tree_add_item(saprouter_tree, hf_saprouter_admin_client_ids, tvb, offset, remaining > 0 ? remaining : 0, ENC_NA);
604
0
        clients_tree = proto_item_add_subtree(ci, ett_saprouter);
605
0
        while (tvb_offset_exists(tvb, offset) && tvb_reported_length_remaining(tvb, offset)>=4){
606
0
          proto_tree_add_item(clients_tree, hf_saprouter_admin_client_id, tvb, offset, 4, ENC_BIG_ENDIAN);
607
0
          offset+=4;
608
0
          client_count_actual+=1;
609
0
        }
610
611
        /* Check if the actual count of IDs differes from the reported number */
612
0
        if ((client_count_actual != client_count) || tvb_reported_length_remaining(tvb, offset)>0){
613
0
          expert_add_info(pinfo, clients_tree, &ei_saprouter_invalid_client_ids);
614
0
        }
615
616
0
        break;
617
0
      }
618
0
      default: {
619
        /* Skip 2 bytes */
620
0
        break;
621
0
      }
622
0
    }
623
624
  /* Route Message Type */
625
0
  } else if (saprouter_type_matches(tvb, offset, eyecatcher_length, SAPROUTER_TYPE_ROUTE_STRING)){
626
0
    uint32_t route_length = 0, route_offset = 0;
627
0
    tvbuff_t *route_tvb = NULL;
628
629
0
    col_set_str(pinfo->cinfo, COL_INFO, "Route message");
630
631
0
    if (tvb_reported_length_remaining(tvb, offset) < SAPROUTER_ROUTE_OFFSET_OFFSET + 4) {
632
0
      expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_route_invalid_length, "Route message is shorter than %u bytes", SAPROUTER_ROUTE_OFFSET_OFFSET + 4);
633
0
      return tvb_reported_length(tvb);
634
0
    }
635
636
    /* Get the route length/offset */
637
0
    route_length = tvb_get_ntohl(tvb, offset + SAPROUTER_ROUTE_LENGTH_OFFSET);
638
0
    route_offset = offset + SAPROUTER_ROUTE_OFFSET_OFFSET + 4;
639
640
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, 0, eyecatcher_length, ENC_ASCII);
641
0
    offset += eyecatcher_length;
642
0
    proto_item_append_text(ti, ", Route message");
643
    /* Add the fields */
644
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_route_version, tvb, offset, 1, ENC_BIG_ENDIAN);
645
0
    offset++;
646
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_ni_version, tvb, offset, 1, ENC_BIG_ENDIAN);
647
0
    offset++;
648
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_entries, tvb, offset, 1, ENC_BIG_ENDIAN);
649
0
    offset++;
650
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_talk_mode, tvb, offset, 1, ENC_BIG_ENDIAN);
651
0
    offset+=3; /* There're two unused bytes there */
652
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_rest_nodes, tvb, offset, 1, ENC_BIG_ENDIAN);
653
0
    offset++;
654
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_route_length, tvb, offset, 4, ENC_BIG_ENDIAN);
655
0
    offset+=4;
656
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_route_offset, tvb, offset, 4, ENC_BIG_ENDIAN);
657
0
    offset+=4;
658
    /* Add the route tree */
659
0
    remaining = tvb_reported_length_remaining(tvb, route_offset);
660
0
    if (route_offset < offset || remaining < 0) {
661
0
      expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_route_invalid_length, "Route string offset is invalid (route_offset=%u)", route_offset);
662
0
      route_length = 0;
663
0
    } else if ((uint32_t)remaining != route_length){
664
0
      expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_route_invalid_length, "Route string length is invalid (remaining=%d, route_length=%d)", remaining, route_length);
665
0
      route_length = (uint32_t)remaining;
666
0
    }
667
0
    ri = proto_tree_add_item(saprouter_tree, hf_saprouter_route, tvb, route_offset, route_length, ENC_NA);
668
0
    route_tree = proto_item_add_subtree(ri, ett_saprouter);
669
670
    /* Dissect the route string */
671
0
    if (route_length > 0) {
672
0
      route_tvb = tvb_new_subset_length(tvb, route_offset, route_length);
673
0
      dissect_routestring(route_tvb, pinfo, route_tree, 0, session_state);
674
0
    }
675
676
    /* If this is the first time we're seeing this packet, mark it as the one where the route was requested */
677
0
    if (!pinfo->fd->visited) {
678
0
      session_state->route_requested_in = pinfo->num;
679
0
    }
680
681
    /* Add the route to the colinfo*/
682
0
    if (session_state->src_hostname){
683
0
      col_append_fstr(pinfo->cinfo, COL_INFO, ", Source: Hostname=%s Service Port=%d", session_state->src_hostname, session_state->src_port);
684
0
      if (session_state->src_password && strlen(session_state->src_password)>0)
685
0
        col_append_fstr(pinfo->cinfo, COL_INFO, " Password=%s", session_state->src_password);
686
0
    }
687
0
    if (session_state->dest_hostname){
688
0
      col_append_fstr(pinfo->cinfo, COL_INFO, ", Destination: Hostname=%s Service Port=%d", session_state->dest_hostname, session_state->dest_port);
689
0
      if (session_state->dest_password && strlen(session_state->dest_password)>0)
690
0
        col_append_fstr(pinfo->cinfo, COL_INFO, " Password=%s", session_state->dest_password);
691
0
    }
692
693
0
    if (session_state->route_accepted && session_state->route_accepted_in) {
694
0
      gi = proto_tree_add_uint(saprouter_tree, hf_saprouter_route_accepted_in, tvb, 0, 0, session_state->route_accepted_in);
695
0
      proto_item_set_generated(gi);
696
0
    }
697
698
  /* Error Information/Control Message Type */
699
0
  } else if (saprouter_type_matches(tvb, offset, eyecatcher_length, SAPROUTER_TYPE_ERR_STRING)){
700
701
    /* Extract the opcode if possible to determine the type of message */
702
0
    if (tvb_offset_exists(tvb, offset + 10)) {
703
0
      opcode = tvb_get_uint8(tvb, offset + 10);
704
0
    } else {
705
0
      opcode = 0;
706
0
    }
707
708
0
    col_set_str(pinfo->cinfo, COL_INFO, (opcode==0)? "Error information" : "Control message");
709
710
0
    uint32_t text_length = 0;
711
712
0
    proto_item_append_text(ti, (opcode==0)? ", Error information" : ", Control message");
713
0
    remaining = tvb_reported_length_remaining(tvb, offset);
714
0
    if (remaining < (int)(eyecatcher_length + SAPROUTER_ERR_FIXED_LEN)) {
715
0
      expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_control_invalid_length, "SAP Router error/control message is shorter than %u fixed bytes", eyecatcher_length + SAPROUTER_ERR_FIXED_LEN);
716
0
      proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, offset, eyecatcher_length, ENC_ASCII);
717
0
      return tvb_reported_length(tvb);
718
0
    }
719
    /* Add the fields */
720
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_type, tvb, offset, eyecatcher_length, ENC_ASCII);
721
0
    offset += eyecatcher_length;
722
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_ni_version, tvb, offset, 1, ENC_BIG_ENDIAN);
723
0
    offset++;
724
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_opcode, tvb, offset, 1, ENC_BIG_ENDIAN);
725
0
    offset+=2; /* There's a unused byte there */
726
0
    proto_tree_add_item(saprouter_tree, hf_saprouter_return_code, tvb, offset, 4, ENC_BIG_ENDIAN);
727
0
    offset+=4;
728
729
0
    text_length = tvb_get_ntohl(tvb, offset);
730
    /* Error Information Message */
731
0
    if (opcode == 0){
732
0
      proto_tree_add_item(saprouter_tree, hf_saprouter_error_length, tvb, offset, 4, ENC_BIG_ENDIAN);
733
0
      offset+=4;
734
0
      remaining = tvb_reported_length_remaining(tvb, offset);
735
0
      if ((text_length > 0) && remaining > 0){
736
0
        if ((uint32_t)remaining < text_length) {
737
0
          expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_control_invalid_length, "SAP Router error text is shorter than its reported length (remaining=%d, text_length=%u)", remaining, text_length);
738
0
          text_length = (uint32_t)remaining;
739
0
        }
740
        /* Add the error string tree */
741
0
        ei = proto_tree_add_item(saprouter_tree, hf_saprouter_error_string, tvb, offset, text_length, ENC_NA);
742
0
        text_tree = proto_item_add_subtree(ei, ett_saprouter);
743
0
        dissect_errorstring(tvb_new_subset_length(tvb, offset, text_length), text_tree, 0);
744
0
        offset += text_length;
745
0
      }
746
747
      /* Add an unknown int field */
748
0
      if (tvb_reported_length_remaining(tvb, offset) >= 4) {
749
0
        proto_tree_add_item(saprouter_tree, hf_saprouter_unknown, tvb, offset, 4, ENC_BIG_ENDIAN);
750
0
      }
751
752
      /* Control Message */
753
0
    } else {
754
      /* Add the opcode name */
755
0
      proto_item_append_text(ti, ", opcode=%s", val_to_str_const(opcode, saprouter_opcode_vals, "Unknown"));
756
0
      col_append_fstr(pinfo->cinfo, COL_INFO, ", opcode=%s", val_to_str_const(opcode, saprouter_opcode_vals, "Unknown"));
757
758
0
      proto_tree_add_item(saprouter_tree, hf_saprouter_control_length, tvb, offset, 4, ENC_BIG_ENDIAN);
759
0
      offset+=4;
760
0
      remaining = tvb_reported_length_remaining(tvb, offset);
761
0
      if ((text_length > 0) && remaining > 0){
762
0
        if ((uint32_t)remaining < text_length) {
763
0
          expert_add_info_format(pinfo, saprouter_tree, &ei_saprouter_control_invalid_length, "SAP Router control text is shorter than its reported length (remaining=%d, text_length=%u)", remaining, text_length);
764
0
          text_length = (uint32_t)remaining;
765
0
        }
766
        /* Add the control string tree */
767
0
        proto_tree_add_item(saprouter_tree, hf_saprouter_control_string, tvb, offset, text_length, ENC_ASCII);
768
0
        offset += text_length;
769
0
      }
770
771
      /* SNC request, mark the conversation as SNC protected and dissect the SNC frame */
772
0
      if (opcode == 70 || opcode == 71){
773
0
        session_state->route_snc_protected = true;
774
0
        if (tvb_reported_length_remaining(tvb, offset) > 0) {
775
0
          dissect_saprouter_snc_frame(tvb, pinfo, tree, offset);
776
0
        }
777
778
      /* Other opcodes */
779
0
      } else {
780
0
        if (tvb_reported_length_remaining(tvb, offset) >= 4) {
781
0
          proto_tree_add_item(saprouter_tree, hf_saprouter_control_unknown, tvb, offset, 4, ENC_ASCII);
782
0
        }
783
0
      }
784
785
0
    }
786
787
  /* Route Acceptance (NI_PONG) Message Type */
788
0
  } else if (tvb_strneql(tvb, offset, SAPROUTER_TYPE_ROUTE_ACCEPT, eyecatcher_length) == 0){
789
    /* Route information available */
790
0
    if (session_state->route_information){
791
      /* If this is the first time we're seen the packet, mark is as the one where the route was accepted */
792
0
      if (!pinfo->fd->visited) {
793
0
        session_state->route_accepted = true;
794
0
        session_state->route_accepted_in = pinfo->num;
795
0
      }
796
797
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);
798
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);
799
800
0
      if (session_state->route_requested_in) {
801
0
        gi = proto_tree_add_uint(saprouter_tree, hf_saprouter_route_requested_in, tvb, 0, 0, session_state->route_requested_in);
802
0
        proto_item_set_generated(gi);
803
0
      }
804
0
    }
805
806
  /* Unknown Message Type */
807
0
  } else {
808
809
0
    col_set_str(pinfo->cinfo, COL_INFO, "Routed message");
810
0
    proto_item_append_text(ti, ", Routed message");
811
812
    /* If the session is protected with SNC, first dissect the SNC frame
813
     * and save the content for further dissection.
814
     */
815
0
    if (session_state->route_snc_protected) {
816
0
      col_append_str(pinfo->cinfo, COL_INFO, ", SNC protected");
817
0
      proto_item_append_text(ti, ", SNC protected");
818
0
      next_tvb = dissect_saprouter_snc_frame(tvb, pinfo, tree, offset);
819
820
    /* If the session is not protected dissect the entire payload */
821
0
    } else {
822
0
      next_tvb = tvb;
823
0
    }
824
825
    /* If the session has information about the route requested */
826
0
    if (session_state->route_information){
827
828
      /* Route accepted */
829
0
      if (session_state->route_accepted){
830
831
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);
832
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);
833
834
0
        if (session_state->route_requested_in) {
835
0
          gi = proto_tree_add_uint(saprouter_tree, hf_saprouter_route_requested_in, tvb, 0, 0, session_state->route_requested_in);
836
0
          proto_item_set_generated(gi);
837
0
        }
838
0
        if (session_state->route_accepted_in) {
839
0
          gi = proto_tree_add_uint(saprouter_tree, hf_saprouter_route_accepted_in, tvb, 0, 0, session_state->route_accepted_in);
840
0
          proto_item_set_generated(gi);
841
0
        }
842
843
      /* Route not accepted but some information available */
844
0
      } else {
845
0
        col_append_str(pinfo->cinfo, COL_INFO, ", to unknown destination");
846
0
        proto_item_append_text(ti, ", to unknown destination");
847
0
      }
848
849
      /* Call the dissector in the NI protocol sub-dissectors table
850
       * according to the route destination port number. */
851
0
      if (next_tvb) {
852
0
        dissect_sap_protocol_payload(next_tvb, offset, pinfo, tree, 0, session_state->dest_port);
853
0
      }
854
855
0
    } else {
856
      /* No route information available */
857
0
      col_append_str(pinfo->cinfo, COL_INFO, ", to unknown destination");
858
0
      proto_item_append_text(ti, ", to unknown destination");
859
0
    }
860
0
  }
861
862
0
  return tvb_reported_length(tvb);
863
0
}
864
865
void
866
proto_register_saprouter(void)
867
16
{
868
16
  static hf_register_info hf[] = {
869
16
    { &hf_saprouter_type,
870
16
      { "Type", "saprouter.type", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
871
872
    /* Niping message */
873
16
    { &hf_saprouter_niping_message,
874
16
      { "Niping message", "saprouter.message", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
875
876
    /* NI Route messages */
877
16
    { &hf_saprouter_route_version,
878
16
      { "Route version", "saprouter.version", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
879
16
    { &hf_saprouter_ni_version,
880
16
      { "NI version", "saprouter.niversion", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
881
16
    { &hf_saprouter_entries,
882
16
      { "Entries", "saprouter.entries", FT_UINT8, BASE_DEC, NULL, 0x0, "Total number of entries", HFILL }},
883
16
    { &hf_saprouter_talk_mode,
884
16
      { "Talk Mode", "saprouter.talkmode", FT_UINT8, BASE_DEC, VALS(saprouter_talk_mode_vals), 0x0, NULL, HFILL }},
885
16
    { &hf_saprouter_rest_nodes,
886
16
      { "Remaining Hops", "saprouter.restnodes", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL }},
887
16
    { &hf_saprouter_route_length,
888
16
      { "Route String Length", "saprouter.routelength", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
889
16
    { &hf_saprouter_route_offset,
890
16
      { "Route String Offset", "saprouter.routeoffset", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
891
16
    { &hf_saprouter_route,
892
16
      { "Route String", "saprouter.routestring", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
893
16
    { &hf_saprouter_route_string,
894
16
      { "Route Hop", "saprouter.routestring", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
895
16
    { &hf_saprouter_route_string_hostname,
896
16
      { "Hostname", "saprouter.routestring.hostname", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
897
16
    { &hf_saprouter_route_string_service,
898
16
      { "Service", "saprouter.routestring.service", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
899
16
    { &hf_saprouter_route_string_password,
900
16
      { "Password", "saprouter.routestring.password", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
901
902
16
    { &hf_saprouter_route_requested_in,
903
16
      { "Route Requested in", "saprouter.requested_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "The route request for this packet is in this packet", HFILL }},
904
16
    { &hf_saprouter_route_accepted_in,
905
16
      { "Route Accepted in", "saprouter.accepted_in", FT_FRAMENUM, BASE_NONE, NULL, 0x0, "The route for this packet was accepted in this packet", HFILL }},
906
907
    /* NI error information / Control messages */
908
16
    { &hf_saprouter_opcode,
909
16
      { "Operation Code", "saprouter.opcode", FT_UINT8, BASE_DEC, VALS(saprouter_opcode_vals), 0x0, NULL, HFILL }},
910
16
    { &hf_saprouter_return_code,
911
16
      { "Return Code", "saprouter.returncode", FT_INT32, BASE_DEC, VALS(saprouter_return_code_vals), 0x0, NULL, HFILL }},
912
16
    { &hf_saprouter_unknown,
913
16
      { "Unknown field", "saprouter.unknown", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
914
915
    /* NI Error Information messages */
916
16
    { &hf_saprouter_error_length,
917
16
      { "Error Information Text Length", "saprouter.errorlength", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
918
16
    { &hf_saprouter_error_string,
919
16
      { "Error Information Text", "saprouter.errortext", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
920
16
    { &hf_saprouter_error_eyecatcher,
921
16
      { "Eyecatcher", "saprouter.errortext.eyecatcher", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
922
16
    { &hf_saprouter_error_counter,
923
16
      { "Counter", "saprouter.errortext.counter", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
924
16
    { &hf_saprouter_error_error,
925
16
      { "Error", "saprouter.errortext.error", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
926
16
    { &hf_saprouter_error_return_code,
927
16
      { "Return code", "saprouter.errortext.returncode", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
928
16
    { &hf_saprouter_error_component,
929
16
      { "Component", "saprouter.errortext.component", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
930
16
    { &hf_saprouter_error_release,
931
16
      { "Release", "saprouter.errortext.release", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
932
16
    { &hf_saprouter_error_version,
933
16
      { "Version", "saprouter.errortext.version", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
934
16
    { &hf_saprouter_error_module,
935
16
      { "Module", "saprouter.errortext.module", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
936
16
    { &hf_saprouter_error_line,
937
16
      { "Line", "saprouter.errortext.line", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
938
16
    { &hf_saprouter_error_detail,
939
16
      { "Detail", "saprouter.errortext.detail", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
940
16
    { &hf_saprouter_error_time,
941
16
      { "Time", "saprouter.errortext.time", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
942
16
    { &hf_saprouter_error_system_call,
943
16
      { "System Call", "saprouter.errortext.system_call", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
944
16
    { &hf_saprouter_error_errorno,
945
16
      { "Error Number", "saprouter.errortext.errorno", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
946
16
    { &hf_saprouter_error_errorno_text,
947
16
      { "Error Number Text", "saprouter.errortext.errorno_text", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
948
16
    { &hf_saprouter_error_location,
949
16
      { "Location", "saprouter.errortext.location", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
950
16
    { &hf_saprouter_error_error_count,
951
16
      { "Error Count", "saprouter.errortext.error_count", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
952
16
    { &hf_saprouter_error_unknown,
953
16
      { "Unknown field", "saprouter.errortext.unknown", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
954
955
    /* Control messages */
956
16
    { &hf_saprouter_control_length,
957
16
      { "Control Text Length", "saprouter.controllength", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
958
16
    { &hf_saprouter_control_string,
959
16
      { "Control Text", "saprouter.controltext", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
960
16
    { &hf_saprouter_control_unknown,
961
16
      { "Control Unknown field", "saprouter.controlunknown", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
962
963
    /* Router Admin messages */
964
16
    { &hf_saprouter_admin_command,
965
16
      { "Admin Command", "saprouter.command", FT_UINT8, BASE_DEC, VALS(saprouter_admin_command_vals), 0x0, NULL, HFILL }},
966
16
    { &hf_saprouter_admin_password,
967
16
      { "Admin Command Info Password", "saprouter.password", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
968
16
    { &hf_saprouter_admin_client_count_short,
969
16
      { "Admin Command Client Count", "saprouter.client_count", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
970
16
    { &hf_saprouter_admin_client_count_int,
971
16
      { "Admin Command Client Count", "saprouter.client_count", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
972
16
    { &hf_saprouter_admin_client_ids,
973
16
      { "Admin Command Client IDs", "saprouter.client_ids", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
974
16
    { &hf_saprouter_admin_client_id,
975
16
      { "Admin Command Client ID", "saprouter.client_id", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
976
16
    { &hf_saprouter_admin_address_mask,
977
16
      { "Admin Command Address Mask", "saprouter.address_mask", FT_STRING, BASE_NONE, NULL, 0x0, NULL, HFILL }},
978
16
  };
979
980
  /* Setup protocol subtree array */
981
16
  static int *ett[] = {
982
16
    &ett_saprouter
983
16
  };
984
985
  /* Register the expert info */
986
16
  static ei_register_info ei[] = {
987
16
    { &ei_saprouter_route_password_found, { "saprouter.routestring.password.found", PI_SECURITY, PI_WARN, "Route password found", EXPFILL }},
988
16
    { &ei_saprouter_info_password_found, { "saprouter.password.found", PI_SECURITY, PI_WARN, "Info password found", EXPFILL }},
989
16
    { &ei_saprouter_route_invalid_length, { "saprouter.routestring.routelength.invalid", PI_MALFORMED, PI_WARN, "The route string length is invalid", EXPFILL }},
990
16
    { &ei_saprouter_invalid_client_ids, { "saprouter.client_ids.invalid", PI_MALFORMED, PI_WARN, "Client IDs list is malformed", EXPFILL }},
991
16
    { &ei_saprouter_control_invalid_length, { "saprouter.control.length.invalid", PI_MALFORMED, PI_WARN, "The error/control message length is invalid", EXPFILL }},
992
16
  };
993
994
16
  module_t *saprouter_module;
995
16
  expert_module_t* saprouter_expert;
996
997
  /* Register the protocol */
998
16
  proto_saprouter = proto_register_protocol("SAP Router Protocol", "SAPROUTER", "saprouter");
999
1000
16
  proto_register_field_array(proto_saprouter, hf, array_length(hf));
1001
16
  proto_register_subtree_array(ett, array_length(ett));
1002
1003
16
  saprouter_expert = expert_register_protocol(proto_saprouter);
1004
16
  expert_register_field_array(saprouter_expert, ei, array_length(ei));
1005
1006
16
  register_dissector("saprouter", dissect_saprouter, proto_saprouter);
1007
1008
  /* Register the preferences */
1009
16
  saprouter_module = prefs_register_protocol(proto_saprouter, proto_reg_handoff_saprouter);
1010
1011
16
  range_convert_str(wmem_epan_scope(), &global_saprouter_port_range, SAPROUTER_PORT_RANGE, MAX_TCP_PORT);
1012
16
  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);
1013
1014
16
  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);
1015
1016
  /* Register the tap*/
1017
16
  credentials_tap = register_tap("credentials");
1018
1019
16
}
1020
1021
1022
/**
1023
 * Helpers for dealing with the port range
1024
 */
1025
static void range_delete_callback (uint32_t port, void *ptr _U_)
1026
0
{
1027
0
  dissector_delete_uint("sapni.port", port, saprouter_handle);
1028
0
}
1029
1030
static void range_add_callback (uint32_t port, void *ptr _U_)
1031
32
{
1032
32
  dissector_add_uint("sapni.port", port, saprouter_handle);
1033
32
}
1034
1035
1036
/**
1037
 * Register Hand off for the SAP Router Protocol
1038
 */
1039
void
1040
proto_reg_handoff_saprouter(void)
1041
16
{
1042
16
  static bool initialized = false;
1043
16
  static range_t *saprouter_port_range;
1044
1045
16
  if (!initialized) {
1046
16
    saprouter_handle = create_dissector_handle(dissect_saprouter, proto_saprouter);
1047
16
    initialized = true;
1048
16
  } else {
1049
0
    range_foreach(saprouter_port_range, range_delete_callback, NULL);
1050
0
    wmem_free(wmem_epan_scope(), saprouter_port_range);
1051
0
  }
1052
1053
16
  saprouter_port_range = range_copy(wmem_epan_scope(), global_saprouter_port_range);
1054
16
  range_foreach(saprouter_port_range, range_add_callback, NULL);
1055
1056
16
}
1057
1058
/*
1059
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
1060
 *
1061
 * Local variables:
1062
 * c-basic-offset: 8
1063
 * tab-width: 8
1064
 * indent-tabs-mode: t
1065
 * End:
1066
 *
1067
 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1068
 * :indentSize=8:tabSize=8:noTabs=false:
1069
 */