Do the "follow TCP stream" stuff before calling the subdissector, so
[obnox/wireshark/wip.git] / packet-clnp.c
index 495ac22a171508e4cf76c2a930c1f54aeb8a8c16..c17f4a929fec629cc2b28f7648f0a1eb1cc14deb 100644 (file)
@@ -1,7 +1,7 @@
 /* packet-clnp.c
  * Routines for ISO/OSI network and transport protocol packet disassembly
  *
- * $Id: packet-clnp.c,v 1.41 2001/12/03 03:59:33 guy Exp $
+ * $Id: packet-clnp.c,v 1.53 2002/04/07 21:54:48 guy Exp $
  * Laurent Deniel <deniel@worldnet.fr>
  * Ralf Schneider <Ralf.Schneider@t-online.de>
  *
@@ -37,7 +37,7 @@
 #include <ctype.h>
 #include <glib.h>
 #include "prefs.h"
-#include "packet.h"
+#include <epan/packet.h>
 #include "reassemble.h"
 #include "packet-osi.h"
 #include "packet-osi-options.h"
@@ -693,8 +693,8 @@ static int osi_decode_DR(tvbuff_t *tvb, int offset,
       break;
   }
 
-  if (check_col(pinfo->fd, COL_INFO))
-    col_append_fstr(pinfo->fd, COL_INFO,
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_fstr(pinfo->cinfo, COL_INFO,
                "DR TPDU src-ref: 0x%04x dst-ref: 0x%04x",
                 src_ref, dst_ref);
 
@@ -788,8 +788,8 @@ static int osi_decode_DT(tvbuff_t *tvb, int offset,
       break;
   }
 
-  if (check_col(pinfo->fd, COL_INFO))
-    col_append_fstr(pinfo->fd, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x %s", 
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_fstr(pinfo->cinfo, COL_INFO, "DT TPDU (%u) dst-ref: 0x%04x %s", 
                 tpdu_nr,
                 dst_ref,
                 (fragment)? "(fragment)" : "");
@@ -911,8 +911,8 @@ static int osi_decode_ED(tvbuff_t *tvb, int offset,
       break;
   } /* li */
 
-  if (check_col(pinfo->fd, COL_INFO))
-    col_append_fstr(pinfo->fd, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x", 
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_fstr(pinfo->cinfo, COL_INFO, "ED TPDU (%u) dst-ref: 0x%04x", 
                 tpdu_nr, dst_ref);
 
   if (tree) {
@@ -989,8 +989,8 @@ static int osi_decode_RJ(tvbuff_t *tvb, int offset,
       break;
   }
 
-  if (check_col(pinfo->fd, COL_INFO))
-    col_append_fstr(pinfo->fd, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x", 
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_fstr(pinfo->cinfo, COL_INFO, "RJ TPDU (%u) dst-ref: 0x%04x", 
                 tpdu_nr, dst_ref);
 
   if (tree) {
@@ -1038,8 +1038,8 @@ static int osi_decode_CC(tvbuff_t *tvb, int offset,
   if (class_option > 4)
     return -1;
 
-  if (check_col(pinfo->fd, COL_INFO))
-    col_append_fstr(pinfo->fd, COL_INFO,
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_fstr(pinfo->cinfo, COL_INFO,
                 "%s TPDU src-ref: 0x%04x dst-ref: 0x%04x",
                 (tpdu == CR_TPDU) ? "CR" : "CC",
                 src_ref,
@@ -1107,8 +1107,8 @@ static int osi_decode_DC(tvbuff_t *tvb, int offset,
 
   src_ref = tvb_get_ntohs(tvb, offset + P_SRC_REF);
 
-  if (check_col(pinfo->fd, COL_INFO))
-    col_append_fstr(pinfo->fd, COL_INFO,
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_fstr(pinfo->cinfo, COL_INFO,
                 "DC TPDU src-ref: 0x%04x dst-ref: 0x%04x", 
                 src_ref,
                 dst_ref);
@@ -1165,8 +1165,8 @@ static int osi_decode_AK(tvbuff_t *tvb, int offset,
 
     tpdu_nr = tvb_get_guint8(tvb, offset + P_TPDU_NR_234);
 
-    if (check_col(pinfo->fd, COL_INFO))
-      col_append_fstr(pinfo->fd, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x", 
+    if (check_col(pinfo->cinfo, COL_INFO))
+      col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x", 
                   tpdu_nr, dst_ref);
 
     if (tree) {
@@ -1209,8 +1209,8 @@ static int osi_decode_AK(tvbuff_t *tvb, int offset,
     tpdu_nr   = tvb_get_ntohl(tvb, offset + P_TPDU_NR_234);
     cdt_in_ak = tvb_get_ntohs(tvb, offset + P_CDT_IN_AK);
 
-    if (check_col(pinfo->fd, COL_INFO))
-      col_append_fstr(pinfo->fd, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x", 
+    if (check_col(pinfo->cinfo, COL_INFO))
+      col_append_fstr(pinfo->cinfo, COL_INFO, "AK TPDU (%u) dst-ref: 0x%04x", 
                   tpdu_nr, dst_ref);
     
     if (tree) {
@@ -1303,8 +1303,8 @@ static int osi_decode_EA(tvbuff_t *tvb, int offset,
       break;
   } /* li */
 
-  if (check_col(pinfo->fd, COL_INFO))
-    col_append_fstr(pinfo->fd, COL_INFO, 
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_fstr(pinfo->cinfo, COL_INFO, 
                 "EA TPDU (%u) dst-ref: 0x%04x", tpdu_nr, dst_ref);
 
   if (tree) {
@@ -1382,8 +1382,8 @@ static int osi_decode_ER(tvbuff_t *tvb, int offset,
       break;
   }
 
-  if (check_col(pinfo->fd, COL_INFO))
-    col_append_fstr(pinfo->fd, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_fstr(pinfo->cinfo, COL_INFO, "ER TPDU dst-ref: 0x%04x", dst_ref);
 
   if (tree) {
     ti = proto_tree_add_item(tree, proto_cotp, tvb, offset, li + 1, FALSE);
@@ -1405,15 +1405,14 @@ static int osi_decode_ER(tvbuff_t *tvb, int offset,
 } /* osi_decode_ER */
 
 static int osi_decode_UD(tvbuff_t *tvb, int offset, 
-                        packet_info *pinfo, proto_tree *tree,
-                        gboolean *subdissector_found)
+                        packet_info *pinfo, proto_tree *tree)
 {
   proto_item *ti;
   proto_tree *cltp_tree = NULL;
   tvbuff_t   *next_tvb;
 
-  if (check_col(pinfo->fd, COL_INFO))
-    col_append_str(pinfo->fd, COL_INFO, "UD TPDU");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_append_str(pinfo->cinfo, COL_INFO, "UD TPDU");
 
   if (tree) {
     ti = proto_tree_add_item(tree, proto_cltp, tvb, offset, li + 1, FALSE);
@@ -1469,17 +1468,17 @@ static gboolean dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo,
 
   /* Initialize the COL_INFO field; each of the TPDUs will have its
      information appended. */
-  if (check_col(pinfo->fd, COL_INFO))
-    col_add_str(pinfo->fd, COL_INFO, "");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_add_str(pinfo->cinfo, COL_INFO, "");
 
   while (tvb_offset_exists(tvb, offset)) {
     if (!first_tpdu) {
-      if (check_col(pinfo->fd, COL_INFO))
-        col_append_str(pinfo->fd, COL_INFO, ", ");
+      if (check_col(pinfo->cinfo, COL_INFO))
+        col_append_str(pinfo->cinfo, COL_INFO, ", ");
     }
     if ((li = tvb_get_guint8(tvb, offset + P_LI)) == 0) {
-      if (check_col(pinfo->fd, COL_INFO))
-        col_append_str(pinfo->fd, COL_INFO, "Length indicator is zero");
+      if (check_col(pinfo->cinfo, COL_INFO))
+        col_append_str(pinfo->cinfo, COL_INFO, "Length indicator is zero");
       if (!first_tpdu)
         call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
       return found_ositp;
@@ -1522,13 +1521,12 @@ static gboolean dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo,
         new_offset = osi_decode_ER(tvb, offset, pinfo, tree);
         break;
       case UD_TPDU :
-        new_offset = osi_decode_UD(tvb, offset, pinfo, tree,
-                                  &subdissector_found);
+        new_offset = osi_decode_UD(tvb, offset, pinfo, tree);
         is_cltp = TRUE;
         break;
       default      :
-        if (first_tpdu && check_col(pinfo->fd, COL_INFO))
-          col_append_fstr(pinfo->fd, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
+        if (first_tpdu && check_col(pinfo->cinfo, COL_INFO))
+          col_append_fstr(pinfo->cinfo, COL_INFO, "Unknown TPDU type (0x%x)", tpdu);
         new_offset = -1;       /* bad PDU type */
         break;
     }
@@ -1542,8 +1540,8 @@ static gboolean dissect_ositp_internal(tvbuff_t *tvb, packet_info *pinfo,
     if (first_tpdu) {
       /* Well, we found at least one valid COTP or CLTP PDU, so I guess this
          is either COTP or CLTP. */
-      if (!subdissector_found && check_col(pinfo->fd, COL_PROTOCOL))
-        col_set_str(pinfo->fd, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
+      if (!subdissector_found && check_col(pinfo->cinfo, COL_PROTOCOL))
+        col_set_str(pinfo->cinfo, COL_PROTOCOL, is_cltp ? "CLTP" : "COTP");
       found_ositp = TRUE;
     }
 
@@ -1587,26 +1585,27 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
   gint        len;
   guint       next_length;
   proto_tree *discpdu_tree;
-  address     save_dl_src;
-  address     save_dl_dst;
-  address     save_net_src;
-  address     save_net_dst;
-  address     save_src;
-  address     save_dst;
+  volatile address save_dl_src;
+  volatile address save_dl_dst;
+  volatile address save_net_src;
+  volatile address save_net_dst;
+  volatile address save_src;
+  volatile address save_dst;
   gboolean    save_in_error_pkt;
   fragment_data *fd_head;
   tvbuff_t   *volatile next_tvb;
-  gboolean update_col_info = TRUE;
+  gboolean    update_col_info = TRUE;
+  gboolean    save_fragmented;
 
-  if (check_col(pinfo->fd, COL_PROTOCOL))
-    col_set_str(pinfo->fd, COL_PROTOCOL, "CLNP");
-  if (check_col(pinfo->fd, COL_INFO))
-    col_clear(pinfo->fd, COL_INFO);
+  if (check_col(pinfo->cinfo, COL_PROTOCOL))
+    col_set_str(pinfo->cinfo, COL_PROTOCOL, "CLNP");
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_clear(pinfo->cinfo, COL_INFO);
 
   cnf_proto_id = tvb_get_guint8(tvb, P_CLNP_PROTO_ID);
   if (cnf_proto_id == NLPID_NULL) {
-    if (check_col(pinfo->fd, COL_INFO))
-      col_set_str(pinfo->fd, COL_INFO, "Inactive subset");
+    if (check_col(pinfo->cinfo, COL_INFO))
+      col_set_str(pinfo->cinfo, COL_INFO, "Inactive subset");
     if (tree) {
       ti = proto_tree_add_item(tree, proto_clnp, tvb, P_CLNP_PROTO_ID, 1, FALSE);
       clnp_tree = proto_item_add_subtree(ti, ett_clnp);
@@ -1687,8 +1686,8 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
      we set it otherwise. */
 
   if (!tvb_bytes_exist(tvb, 0, cnf_hdr_len)) {
-    if (check_col(pinfo->fd, COL_INFO))
-      col_add_fstr(pinfo->fd, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
+    if (check_col(pinfo->cinfo, COL_INFO))
+      col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
   }
 
   segment_length = tvb_get_ntohs(tvb, P_CLNP_SEGLEN);
@@ -1805,7 +1804,7 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 
     dissect_osi_options( 0xff, 
                          opt_len,
-                         tvb, offset, pinfo, clnp_tree ); 
+                         tvb, offset, clnp_tree ); 
   }
 
   /* Length of CLNP datagram plus headers above it. */
@@ -1813,38 +1812,43 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 
   offset = cnf_hdr_len;
 
-  /* For now, dissect the payload of segments other than the initial
-     segment as data, rather than handing them off to the transport
-     protocol, just as we do with fragments other than the first
-     fragment in a fragmented IP datagram; in the future, we will
-     probably reassemble fragments for IP, and may reassemble segments
-     for CLNP. */
-  /* If clnp_reassemble is on and this is a segment, then just add the segment
-   * to the hashtable.
+  /* If clnp_reassemble is on, and this is a segment, we have all the
+   * data in the segment, and the checksum is valid, then just add the
+   * segment to the hashtable.
    */
+  save_fragmented = pinfo->fragmented;
   if (clnp_reassemble && (cnf_type & CNF_SEG_OK) &&
-       ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0)) {
-    /* We're reassembling, and this is part of a segmented datagram.
-       Add the segment to the hash table if the checksum is ok
-       and the frame isn't truncated. */
-    if (cksum_status != CKSUM_NOT_OK &&
-       (tvb_reported_length(tvb) <= tvb_length(tvb))) {
-      fd_head = fragment_add(tvb, offset, pinfo, du_id, clnp_segment_table,
-                            segment_offset, segment_length - cnf_hdr_len,
-                            cnf_type & CNF_MORE_SEGS);
-    } else {
-      fd_head=NULL;
-    }
+       ((cnf_type & CNF_MORE_SEGS) || segment_offset != 0) &&
+       (tvb_reported_length(tvb) <= tvb_length(tvb)) &&
+       cksum_status != CKSUM_NOT_OK) {
+    fd_head = fragment_add(tvb, offset, pinfo, du_id, clnp_segment_table,
+                          segment_offset, segment_length - cnf_hdr_len,
+                          cnf_type & CNF_MORE_SEGS);
 
     if (fd_head != NULL) {
       fragment_data *fd;
       proto_tree *ft=NULL;
       proto_item *fi=NULL;
 
-      /* OK, we have the complete reassembled payload. */
+      /* OK, we have the complete reassembled payload.
+         Allocate a new tvbuff, referring to the reassembled payload. */
+      next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen,
+       fd_head->datalen);
+
+      /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
+         were handed refers, so it'll get cleaned up when that tvbuff
+         is cleaned up. */
+      tvb_set_child_real_data_tvbuff(tvb, next_tvb);
+
+      /* Add the defragmented data to the data source list. */
+      add_new_data_source(pinfo->fd, next_tvb, "Reassembled CLNP");
+
+      /* It's not fragmented. */
+      pinfo->fragmented = FALSE;
+
       /* show all segments */
       fi = proto_tree_add_item(clnp_tree, hf_clnp_segments, 
-                tvb, 0, 0, FALSE);
+                next_tvb, 0, -1, FALSE);
       ft = proto_item_add_subtree(fi, ett_clnp_segments);
       for (fd = fd_head->next; fd != NULL; fd = fd->next){
         if (fd->flags & (FD_OVERLAP|FD_OVERLAPCONFLICT
@@ -1863,8 +1867,8 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
             hf = hf_clnp_segment;
           }
           fei = proto_tree_add_none_format(ft, hf, 
-                   tvb, 0, 0,
-                   "Frame:%d payload:%d-%d",
+                   next_tvb, fd->offset, fd->len,
+                   "Frame:%u payload:%u-%u",
                    fd->frame,
                    fd->offset,
                    fd->offset+fd->len-1
@@ -1872,29 +1876,29 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
           fet = proto_item_add_subtree(fei, ett_clnp_segment);
           if (fd->flags&FD_OVERLAP) {
             proto_tree_add_boolean(fet, 
-                 hf_clnp_segment_overlap, tvb, 0, 0, 
+                 hf_clnp_segment_overlap, next_tvb, 0, 0, 
                  TRUE);
           }
           if (fd->flags&FD_OVERLAPCONFLICT) {
             proto_tree_add_boolean(fet, 
-                 hf_clnp_segment_overlap_conflict, tvb, 0, 0, 
+                 hf_clnp_segment_overlap_conflict, next_tvb, 0, 0, 
                  TRUE);
           }
           if (fd->flags&FD_MULTIPLETAILS) {
             proto_tree_add_boolean(fet, 
-                 hf_clnp_segment_multiple_tails, tvb, 0, 0, 
+                 hf_clnp_segment_multiple_tails, next_tvb, 0, 0, 
                  TRUE);
           }
           if (fd->flags&FD_TOOLONGFRAGMENT) {
             proto_tree_add_boolean(fet, 
-                 hf_clnp_segment_too_long_segment, tvb, 0, 0, 
+                 hf_clnp_segment_too_long_segment, next_tvb, 0, 0, 
                  TRUE);
           }
         } else {
           /* nothing of interest for this segment */
           proto_tree_add_none_format(ft, hf_clnp_segment, 
-                   tvb, 0, 0,
-                   "Frame:%d payload:%d-%d",
+                   next_tvb, fd->offset, fd->len,
+                   "Frame:%u payload:%u-%u",
                    fd->frame,
                    fd->offset,
                    fd->offset+fd->len-1
@@ -1903,26 +1907,11 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
       }
       if (fd_head->flags & (FD_OVERLAPCONFLICT
                         |FD_MULTIPLETAILS|FD_TOOLONGFRAGMENT) ) {
-        if (check_col(pinfo->fd, COL_INFO)) {
-          col_set_str(pinfo->fd, COL_INFO, "[Illegal segments]");
+        if (check_col(pinfo->cinfo, COL_INFO)) {
+          col_set_str(pinfo->cinfo, COL_INFO, "[Illegal segments]");
           update_col_info = FALSE;
         }
       }
-
-      /* Allocate a new tvbuff, referring to the reassembled payload. */
-      next_tvb = tvb_new_real_data(fd_head->data, fd_head->datalen,
-       fd_head->datalen, "Reassembled");
-
-      /* Add the tvbuff to the list of tvbuffs to which the tvbuff we
-         were handed refers, so it'll get cleaned up when that tvbuff
-         is cleaned up. */
-      tvb_set_child_real_data_tvbuff(tvb, next_tvb);
-
-      /* Add the defragmented data to the data source list. */
-      pinfo->fd->data_src = g_slist_append(pinfo->fd->data_src, next_tvb);
-
-      /* It's not fragmented. */
-      pinfo->fragmented = FALSE;
     } else {
       /* We don't have the complete reassembled payload. */
       next_tvb = NULL;
@@ -1955,13 +1944,14 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 
   if (next_tvb == NULL) {
     /* Just show this as a segment. */
-    if (check_col(pinfo->fd, COL_INFO))
-      col_add_fstr(pinfo->fd, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
+    if (check_col(pinfo->cinfo, COL_INFO))
+      col_add_fstr(pinfo->cinfo, COL_INFO, "Fragmented %s NPDU %s(off=%u)",
                pdu_type_string, flag_string, segment_offset);
 
     /* As we haven't reassembled anything, we haven't changed "pi", so
        we don't have to restore it. */
     call_dissector(data_handle,tvb_new_subset(tvb, offset,-1,tvb_reported_length_remaining(tvb,offset)), pinfo, tree);
+    pinfo->fragmented = save_fragmented;
     return;
   }
 
@@ -1975,8 +1965,10 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
          PDU, skip that? */
 
       if (nsel == (char)tp_nsap_selector || always_decode_transport) { 
-        if (dissect_ositp_internal(next_tvb, pinfo, tree, FALSE))
+        if (dissect_ositp_internal(next_tvb, pinfo, tree, FALSE)) {
+          pinfo->fragmented = save_fragmented;
           return;      /* yes, it appears to be COTP or CLTP */
+        }
       }
       break;
 
@@ -1984,8 +1976,8 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
       /* The payload is the header and "none, some, or all of the data
          part of the discarded PDU", i.e. it's like an ICMP error;
         dissect it as a CLNP PDU. */
-      if (check_col(pinfo->fd, COL_INFO))
-        col_add_fstr(pinfo->fd, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
+      if (check_col(pinfo->cinfo, COL_INFO))
+        col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
       if (tree) {
         next_length = tvb_length_remaining(tvb, offset);
         if (next_length != 0) {
@@ -1993,7 +1985,7 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
              Make the columns non-writable, so the packet isn't shown
              in the summary based on what the discarded PDU's contents
              are. */
-          col_set_writable(pinfo->fd, FALSE);
+          col_set_writable(pinfo->cinfo, FALSE);
 
           /* Also, save the current values of the addresses, and restore
              them when we're finished dissecting the contained packet, so
@@ -2043,6 +2035,7 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
           pinfo->dst = save_dst;
         }
       }
+      pinfo->fragmented = save_fragmented;
       return;  /* we're done with this PDU */
 
     case ERQ_NPDU:
@@ -2051,10 +2044,10 @@ static void dissect_clnp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
       break;
     }
   }
-  if (check_col(pinfo->fd, COL_INFO))
-    col_add_fstr(pinfo->fd, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
+  if (check_col(pinfo->cinfo, COL_INFO))
+    col_add_fstr(pinfo->cinfo, COL_INFO, "%s NPDU %s", pdu_type_string, flag_string);
   call_dissector(data_handle,next_tvb, pinfo, tree);
-
+  pinfo->fragmented = save_fragmented;
 } /* dissect_clnp */
 
 static void
@@ -2204,4 +2197,5 @@ proto_reg_handoff_clnp(void)
        clnp_handle = create_dissector_handle(dissect_clnp, proto_clnp);
        dissector_add("osinl", NLPID_ISO8473_CLNP, clnp_handle);
        dissector_add("osinl", NLPID_NULL, clnp_handle); /* Inactive subset */
+       dissector_add("x.25.spi", NLPID_ISO8473_CLNP, clnp_handle);
 }