Home | History | Annotate | Download | only in tcpdump
      1 /* Copyright (c) 2015, bugyo
      2  * All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are met:
      6  * 1. Redistributions of source code must retain the above copyright notice,
      7  *    this list of conditions and the following disclaimer.
      8  * 2. Redistributions in binary form must reproduce the above copyright notice,
      9  *    this list of conditions and the following disclaimer in the documentation
     10  *    and/or other materials provided with the distribution.
     11  *
     12  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     13  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     14  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     15  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
     16  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     17  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     18  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     19  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     20  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     21  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     22  */
     23 
     24 /* \summary: Network Service Header (NSH) printer */
     25 
     26 /* specification: draft-ietf-sfc-nsh-01 */
     27 
     28 #ifdef HAVE_CONFIG_H
     29 #include "config.h"
     30 #endif
     31 
     32 #include <netdissect-stdinc.h>
     33 
     34 #include "netdissect.h"
     35 #include "extract.h"
     36 
     37 static const char tstr[] = " [|NSH]";
     38 static const struct tok nsh_flags [] = {
     39     { 0x20, "O" },
     40     { 0x10, "C" },
     41     { 0, NULL }
     42 };
     43 
     44 #define NSH_BASE_HDR_LEN 4
     45 #define NSH_SERVICE_PATH_HDR_LEN 4
     46 #define NSH_HDR_WORD_SIZE 4U
     47 
     48 void
     49 nsh_print(netdissect_options *ndo, const u_char *bp, u_int len)
     50 {
     51     int n, vn;
     52     uint8_t ver;
     53     uint8_t flags;
     54     uint8_t length;
     55     uint8_t md_type;
     56     uint8_t next_protocol;
     57     uint32_t service_path_id;
     58     uint8_t service_index;
     59     uint32_t ctx;
     60     uint16_t tlv_class;
     61     uint8_t tlv_type;
     62     uint8_t tlv_len;
     63     u_int next_len;
     64 
     65     /* print Base Header and Service Path Header */
     66     if (len < NSH_BASE_HDR_LEN + NSH_SERVICE_PATH_HDR_LEN)
     67         goto trunc;
     68 
     69     ND_TCHECK2(*bp, NSH_BASE_HDR_LEN + NSH_SERVICE_PATH_HDR_LEN);
     70 
     71     ver = (uint8_t)(*bp >> 6);
     72     flags = *bp;
     73     bp += 1;
     74     length = *bp;
     75     bp += 1;
     76     md_type = *bp;
     77     bp += 1;
     78     next_protocol = *bp;
     79     bp += 1;
     80     service_path_id = EXTRACT_24BITS(bp);
     81     bp += 3;
     82     service_index = *bp;
     83     bp += 1;
     84 
     85     ND_PRINT((ndo, "NSH, "));
     86     if (ndo->ndo_vflag > 1) {
     87         ND_PRINT((ndo, "ver %d, ", ver));
     88     }
     89     ND_PRINT((ndo, "flags [%s], ", bittok2str_nosep(nsh_flags, "none", flags)));
     90     if (ndo->ndo_vflag > 2) {
     91         ND_PRINT((ndo, "length %d, ", length));
     92         ND_PRINT((ndo, "md type 0x%x, ", md_type));
     93     }
     94     if (ndo->ndo_vflag > 1) {
     95         ND_PRINT((ndo, "next-protocol 0x%x, ", next_protocol));
     96     }
     97     ND_PRINT((ndo, "service-path-id 0x%06x, ", service_path_id));
     98     ND_PRINT((ndo, "service-index 0x%x", service_index));
     99 
    100     /* Make sure we have all the headers */
    101     if (len < length * NSH_HDR_WORD_SIZE)
    102         goto trunc;
    103 
    104     ND_TCHECK2(*bp, length * NSH_HDR_WORD_SIZE);
    105 
    106     /*
    107      * length includes the lengths of the Base and Service Path headers.
    108      * That means it must be at least 2.
    109      */
    110     if (length < 2)
    111         goto trunc;
    112 
    113     /*
    114      * Print, or skip, the Context Headers.
    115      * (length - 2) is the length of those headers.
    116      */
    117     if (ndo->ndo_vflag > 2) {
    118         if (md_type == 0x01) {
    119             for (n = 0; n < length - 2; n++) {
    120                 ctx = EXTRACT_32BITS(bp);
    121                 bp += NSH_HDR_WORD_SIZE;
    122                 ND_PRINT((ndo, "\n        Context[%02d]: 0x%08x", n, ctx));
    123             }
    124         }
    125         else if (md_type == 0x02) {
    126             n = 0;
    127             while (n < length - 2) {
    128                 tlv_class = EXTRACT_16BITS(bp);
    129                 bp += 2;
    130                 tlv_type  = *bp;
    131                 bp += 1;
    132                 tlv_len   = *bp;
    133                 bp += 1;
    134 
    135                 ND_PRINT((ndo, "\n        TLV Class %d, Type %d, Len %d",
    136                           tlv_class, tlv_type, tlv_len));
    137 
    138                 n += 1;
    139 
    140                 if (length - 2 < n + tlv_len) {
    141                     ND_PRINT((ndo, " ERROR: invalid-tlv-length"));
    142                     return;
    143                 }
    144 
    145                 for (vn = 0; vn < tlv_len; vn++) {
    146                     ctx = EXTRACT_32BITS(bp);
    147                     bp += NSH_HDR_WORD_SIZE;
    148                     ND_PRINT((ndo, "\n            Value[%02d]: 0x%08x", vn, ctx));
    149                 }
    150                 n += tlv_len;
    151             }
    152         }
    153         else {
    154             ND_PRINT((ndo, "ERROR: unknown-next-protocol"));
    155             return;
    156         }
    157     }
    158     else {
    159         bp += (length - 2) * NSH_HDR_WORD_SIZE;
    160     }
    161     ND_PRINT((ndo, ndo->ndo_vflag ? "\n    " : ": "));
    162 
    163     /* print Next Protocol */
    164     next_len = len - length * NSH_HDR_WORD_SIZE;
    165     switch (next_protocol) {
    166     case 0x1:
    167         ip_print(ndo, bp, next_len);
    168         break;
    169     case 0x2:
    170         ip6_print(ndo, bp, next_len);
    171         break;
    172     case 0x3:
    173         ether_print(ndo, bp, next_len, ndo->ndo_snapend - bp, NULL, NULL);
    174         break;
    175     default:
    176         ND_PRINT((ndo, "ERROR: unknown-next-protocol"));
    177         return;
    178     }
    179 
    180     return;
    181 
    182 trunc:
    183     ND_PRINT((ndo, "%s", tstr));
    184 }
    185 
    186