aboutsummaryrefslogtreecommitdiffstats
path: root/epan/osi-utils.c
blob: 0b2c19da1e888ae9047438c1ffbc78ca15cd4a17 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
/* osi-utils.c
 * Routines for ISO/OSI network and transport protocol packet disassembly
 * Main entrance point and common functions
 *
 * Laurent Deniel <laurent.deniel@free.fr>
 * Ralf Schneider <Ralf.Schneider@t-online.de>
 *
 * Wireshark - Network traffic analyzer
 * By Gerald Combs <gerald@wireshark.org>
 * Copyright 1998 Gerald Combs
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#include "config.h"

#include <stdio.h>
#include <string.h>
#include <glib.h>

#include "tvbuff.h"
#include "osi-utils.h"
#include "address.h"
#include "address_types.h"

static void print_nsap_net_buf( const guint8 *, int, gchar *, int);
static void print_area_buf ( const guint8 *, int, gchar *, int);
static void print_address_prefix_buf ( const guint8 *, int, gchar *, int);

/*
 * XXX - shouldn't there be a centralized routine for dissecting NSAPs?
 * See also "dissect_atm_nsap()" in epan/dissectors/packet-arp.c and
 * "dissect_nsap()" in epan/dissectors/packet-isup.c.
 */
gchar *
print_nsap_net( tvbuff_t *tvb, const gint offset, int length )
{
  gchar *cur;

  cur = (gchar *)wmem_alloc(wmem_packet_scope(), MAX_NSAP_LEN * 3 + 50);
  print_nsap_net_buf( tvb_get_ptr(tvb, offset, length), length, cur, MAX_NSAP_LEN * 3 + 50);
  return( cur );
}

static void
print_nsap_net_buf( const guint8 *ad, int length, gchar *buf, int buf_len)
{
  gchar *cur;

  /* to do : NSAP / NET decoding */

  if ( (length <= 0 ) || ( length > MAX_NSAP_LEN ) ) {
    g_strlcpy(buf, "<Invalid length of NSAP>", buf_len);
    return;
  }
  cur = buf;
  if ( ( length == RFC1237_NSAP_LEN ) || ( length == RFC1237_NSAP_LEN + 1 ) ) {
    print_area_buf(ad, RFC1237_FULLAREA_LEN, cur, buf_len);
    cur += strlen( cur );
    print_system_id_buf( ad + RFC1237_FULLAREA_LEN, RFC1237_SYSTEMID_LEN, cur, (int) (buf_len-(cur-buf)));
    cur += strlen( cur );
    cur += g_snprintf(cur, (gulong) (buf_len-(cur-buf)), "[%02x]",
                    ad[ RFC1237_FULLAREA_LEN + RFC1237_SYSTEMID_LEN ] );
    if ( length == RFC1237_NSAP_LEN + 1 ) {
      g_snprintf(cur, (int) (buf_len-(cur-buf)), "-%02x", ad[ length -1 ] );
    }
  }
  else {    /* probably format as standard */
    /* XXX - this is an NSAP, not an area address/address prefix */
    print_area_buf( ad, length, buf, buf_len);
  }
} /* print_nsap */

gchar *
print_system_id(wmem_allocator_t* scope, const guint8 *ad, int length )
{
  gchar        *cur;

  cur = (gchar *)wmem_alloc(scope, MAX_SYSTEMID_LEN * 3 + 5);
  print_system_id_buf(ad, length, cur, MAX_SYSTEMID_LEN * 3 + 5);
  return( cur );
}

gchar *
tvb_print_system_id( tvbuff_t *tvb, const gint offset, int length )
{
  return( print_system_id(wmem_packet_scope(), tvb_get_ptr(tvb, offset, length), length) );
}

void
print_system_id_buf( const guint8 *ad, int length, gchar *buf, int buf_len)
{
  gchar        *cur;
  int           tmp;

  if ( ( length <= 0 ) || ( length > MAX_SYSTEMID_LEN ) ) {
    g_strlcpy(buf, "<Invalid length of SYSTEM ID>", buf_len);
    return;
  }

  cur = buf;
  if ( ( 6 == length ) || /* System-ID */
       ( 7 == length ) || /* LAN-ID */
       ( 8 == length )) { /* LSP-ID */
    cur += g_snprintf(cur, buf_len, "%02x%02x.%02x%02x.%02x%02x", ad[0], ad[1],
                    ad[2], ad[3], ad[4], ad[5] );
    if ( ( 7 == length ) ||
         ( 8 == length )) {
        cur += g_snprintf(cur, (gulong) (buf_len-(cur-buf)), ".%02x", ad[6] );
    }
    if ( 8 == length ) {
        g_snprintf(cur, (gulong) (buf_len-(cur-buf)), "-%02x", ad[7] );
    }
  }
  else {
    tmp = 0;
    while ( tmp < length / 4 ) { /* 16 / 4 == 4 > four Octets left to print */
      cur += g_snprintf(cur, (gulong) (buf_len-(cur-buf)), "%02x", ad[tmp++] );
      cur += g_snprintf(cur, (gulong) (buf_len-(cur-buf)), "%02x", ad[tmp++] );
      cur += g_snprintf(cur, (gulong) (buf_len-(cur-buf)), "%02x", ad[tmp++] );
      cur += g_snprintf(cur, (gulong) (buf_len-(cur-buf)), "%02x.", ad[tmp++] );
    }
    if ( 1 == tmp ) {   /* Special case for Designated IS */
      cur--;
      g_snprintf(cur, (gulong) (buf_len-(cur-buf)), ".%02x", ad[tmp] );
    }
    else {
      for ( ; tmp < length; ) {  /* print the rest without dot */
        cur += g_snprintf(cur, (gulong) (buf_len-(cur-buf)), "%02x", ad[tmp++] );
      }
    }
  }
}

gchar *
print_area(tvbuff_t *tvb, const gint offset, int length)
{
  gchar *cur;

  cur = (gchar *)wmem_alloc(wmem_packet_scope(), MAX_AREA_LEN * 3 + 20);
  print_area_buf(tvb_get_ptr(tvb, offset, length), length, cur, MAX_AREA_LEN * 3 + 20);
  return cur;
}

/*
 * Note: length is in units of half-octets.
 */
gchar *
print_address_prefix(tvbuff_t *tvb, const gint offset, int length)
{
  gchar *cur;

  cur = (gchar *)wmem_alloc(wmem_packet_scope(), MAX_AREA_LEN * 3 + 20);
  print_address_prefix_buf(tvb_get_ptr(tvb, offset, (length+1)/2), length, cur, MAX_AREA_LEN * 3 + 20);
  return cur;
}

/*
 * Note: length is in units of octets.
 */
static void
print_area_buf(const guint8 *ad, int length, gchar *buf, int buf_len)
{
  print_address_prefix_buf(ad, length*2, buf, buf_len);
}

/*
 * Note: length is in units of half-octets.
 */
static void
print_address_prefix_buf(const guint8 *ad, int length, gchar *buf, int buf_len)
{
  gchar *cur;
  int  tmp  = 0;

  /* to do : all real area decoding now: NET is assumed if id len is 1 more byte
   */
  if (length <= 0 || length > MAX_AREA_LEN*2) {
    g_strlcpy(buf, "<Invalid length of AREA>", buf_len);
    return;
  }

  cur = buf;
  /* Check the AFI and length. */
  if ( (  ( NSAP_IDI_ISO_DCC_BIN      == *ad )
       || ( NSAP_IDI_ISO_6523_ICD_BIN == *ad )
       )
       &&
       (  ( RFC1237_FULLAREA_LEN*2       ==  length )
       || ( (RFC1237_FULLAREA_LEN + 1)*2 ==  length )
       )
     ) {    /* AFI is good and length is long enough  */

    /* The AFI is either ISO DCC, binary or ISO 6523-ICD, binary,
     * and the area length corresponds either to the area length
     * for RFC 1237 (GOSIP) addresses or that length + 1.
     *
     * XXX - RFC 1237 doesn't mention ISO DCC, binary, as a valid
     * AFI; is that from GOSIP Version 1?  If it's ISO DCC, binary,
     * the IDI is 3 digits, i.e. 1 1/2 octets.
     */
    /* there used to be a check for (length > RFC1237_FULLAREA_LEN + 1) here,
     * in order to report an invalied length of AREA for DCC / ISO 6523 AFI,
     * but that can *never* be the case because the if() test above explicitly
     * tests for (length == RFC1237_FULLAREA_LEN) or (length == RFC1237_FULLAREA_LEN + 1)
     */

    /* Show the one-octet AFI, the two-octet IDI, the one-octet DFI, the
     * 3-octet AA, and the 2 reserved octets.
     */
    cur += g_snprintf(cur, (gulong) (buf_len-(cur-buf)), "[%02x|%02x:%02x][%02x|%02x:%02x:%02x|%02x:%02x]",
                    ad[0], ad[1], ad[2], ad[3], ad[4],
                    ad[5], ad[6], ad[7], ad[8] );
    /* Show the 2-octet RD and the 2-octet Area. */
    cur += g_snprintf(cur, (gulong) (buf_len-(cur-buf)), "[%02x:%02x|%02x:%02x]",
                    ad[9], ad[10],  ad[11], ad[12] );
    /* Show whatever the heck this is; it's not specified by RFC 1237,
     * but we also handle 14-octet areas.  Is it the "Designated IS"
     * stuff mentioned below?  (I didn't find anything in the IS-IS
     * spec about that.)
     */
    if ( (RFC1237_FULLAREA_LEN + 1)*2 == length )
      g_snprintf(cur, (gulong) (buf_len-(cur-buf)), "-[%02x]", ad[13] );
  }
  else {
    /* This doesn't look like a full RFC 1237 IS-IS area, so all we know
     * is that the first octet is an AFI.  Print it separately from all
     * the other octets.
     */
    if ( length == RFC1237_AREA_LEN*2 ) {
      /* XXX - RFC1237_AREA_LEN, which is 3 octets, doesn't seem to
       * correspond to anything in RFC 1237.  Where did it come from?
       */
      g_snprintf(buf, buf_len, "%02x.%02x%02x", ad[0], ad[1], ad[2] );
      return;
    }
    if ( length == 4*2 ) {
      g_snprintf(buf, buf_len, "%02x%02x%02x%02x", ad[0], ad[1], ad[2], ad[3] );
      return;
    }
    while ( tmp < length / 8 ) {      /* 32/8==4 > four Octets left to print */
      cur += g_snprintf(cur, (gulong) (buf_len-(cur-buf)), "%02x", ad[tmp++] );
      cur += g_snprintf(cur, (gulong) (buf_len-(cur-buf)), "%02x", ad[tmp++] );
      cur += g_snprintf(cur, (gulong) (buf_len-(cur-buf)), "%02x", ad[tmp++] );
      cur += g_snprintf(cur, (gulong) (buf_len-(cur-buf)), "%02x.", ad[tmp++] );
    }
    if ( 2 == tmp ) {                     /* Special case for Designated IS */
      cur--;
      g_snprintf(cur, (gulong) (buf_len-(cur-buf)), "-%02x", ad[tmp] );
    }
    else {
      for ( ; tmp < length / 2; ) {  /* print the rest without dot or dash */
        cur += g_snprintf(cur, (gulong) (buf_len-(cur-buf)), "%02x", ad[tmp++] );
      }
      /* Odd half-octet? */
      if (length & 1) {
        /* Yes - print it (it's the upper half-octet) */
        g_snprintf(cur, (gulong) (buf_len-(cur-buf)), "%x", (ad[tmp] & 0xF0)>>4 );
      }
    }
  }
} /* print_address_prefix_buf */

/******************************************************************************
 * OSI Address Type
 ******************************************************************************/
static int osi_address_type = -1;

static int osi_address_to_str(const address* addr, gchar *buf, int buf_len)
{
    print_nsap_net_buf((const guint8 *)addr->data, addr->len, buf, buf_len);
    return (int)strlen(buf)+1;
}

static int osi_address_str_len(const address* addr _U_)
{
    return MAX_NSAP_LEN * 3 + 50;
}

int get_osi_address_type(void)
{
    return osi_address_type;
}

void register_osi_address_type(void)
{
    if (osi_address_type != -1)
        return;

    osi_address_type = address_type_dissector_register("AT_OSI", "OSI Address", osi_address_to_str, osi_address_str_len, NULL, NULL, NULL, NULL, NULL);
}


/*
 * Editor modelines
 *
 * Local Variables:
 * c-basic-offset: 2
 * tab-width: 8
 * indent-tabs-mode: nil
 * End:
 *
 * ex: set shiftwidth=2 tabstop=8 expandtab:
 * :indentSize=2:tabSize=8:noTabs=true:
 */