Home | History | Annotate | Line # | Download | only in dist
print-sl.c revision 1.9
      1 /*
      2  * Copyright (c) 1989, 1990, 1991, 1993, 1994, 1995, 1996, 1997
      3  *	The Regents of the University of California.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that: (1) source code distributions
      7  * retain the above copyright notice and this paragraph in its entirety, (2)
      8  * distributions including binary code include the above copyright notice and
      9  * this paragraph in its entirety in the documentation or other materials
     10  * provided with the distribution, and (3) all advertising materials mentioning
     11  * features or use of this software display the following acknowledgement:
     12  * ``This product includes software developed by the University of California,
     13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
     14  * the University nor the names of its contributors may be used to endorse
     15  * or promote products derived from this software without specific prior
     16  * written permission.
     17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
     18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     20  */
     21 
     22 #include <sys/cdefs.h>
     23 #ifndef lint
     24 __RCSID("$NetBSD: print-sl.c,v 1.9 2019/10/01 16:06:16 christos Exp $");
     25 #endif
     26 
     27 /* \summary: Compressed Serial Line Internet Protocol printer */
     28 
     29 #ifdef HAVE_CONFIG_H
     30 #include "config.h"
     31 #endif
     32 
     33 #include <netdissect-stdinc.h>
     34 
     35 #include "netdissect.h"
     36 #include "extract.h"
     37 
     38 #include "ip.h"
     39 #include "tcp.h"
     40 #include "slcompress.h"
     41 
     42 /*
     43  * definitions of the pseudo- link-level header attached to slip
     44  * packets grabbed by the packet filter (bpf) traffic monitor.
     45  */
     46 #define SLIP_HDRLEN 16
     47 
     48 #define SLX_DIR 0
     49 #define SLX_CHDR 1
     50 #define CHDR_LEN 15
     51 
     52 #define SLIPDIR_IN 0
     53 #define SLIPDIR_OUT 1
     54 
     55 static const char tstr[] = "[|slip]";
     56 
     57 static u_int lastlen[2][256];
     58 static u_int lastconn = 255;
     59 
     60 static int sliplink_print(netdissect_options *, const u_char *, const struct ip *, u_int);
     61 static int compressed_sl_print(netdissect_options *, const u_char *, const struct ip *, u_int, int);
     62 
     63 u_int
     64 sl_if_print(netdissect_options *ndo,
     65             const struct pcap_pkthdr *h, const u_char *p)
     66 {
     67 	register u_int caplen = h->caplen;
     68 	register u_int length = h->len;
     69 	register const struct ip *ip;
     70 
     71 	if (caplen < SLIP_HDRLEN || length < SLIP_HDRLEN) {
     72 		ND_PRINT((ndo, "%s", tstr));
     73 		return (caplen);
     74 	}
     75 
     76 	caplen -= SLIP_HDRLEN;
     77 	length -= SLIP_HDRLEN;
     78 
     79 	ip = (const struct ip *)(p + SLIP_HDRLEN);
     80 
     81 	if (ndo->ndo_eflag)
     82 		if (sliplink_print(ndo, p, ip, length) == -1) {
     83 			ND_PRINT((ndo, "%s", tstr));
     84 			return (caplen + SLIP_HDRLEN);
     85 	}
     86 
     87 	if (caplen < 1 || length < 1) {
     88 		ND_PRINT((ndo, "%s", tstr));
     89 		return (caplen + SLIP_HDRLEN);
     90 	}
     91 
     92 	switch (IP_V(ip)) {
     93 	case 4:
     94 	        ip_print(ndo, (const u_char *)ip, length);
     95 		break;
     96 	case 6:
     97 		ip6_print(ndo, (const u_char *)ip, length);
     98 		break;
     99 	default:
    100 		ND_PRINT((ndo, "ip v%d", IP_V(ip)));
    101 	}
    102 
    103 	return (SLIP_HDRLEN);
    104 }
    105 
    106 u_int
    107 sl_bsdos_if_print(netdissect_options *ndo,
    108                   const struct pcap_pkthdr *h, const u_char *p)
    109 {
    110 	register u_int caplen = h->caplen;
    111 	register u_int length = h->len;
    112 	register const struct ip *ip;
    113 
    114 	if (caplen < SLIP_HDRLEN) {
    115 		ND_PRINT((ndo, "%s", tstr));
    116 		return (caplen);
    117 	}
    118 
    119 	length -= SLIP_HDRLEN;
    120 
    121 	ip = (const struct ip *)(p + SLIP_HDRLEN);
    122 
    123 #ifdef notdef
    124 	if (ndo->ndo_eflag)
    125 		sliplink_print(ndo, p, ip, length);
    126 #endif
    127 
    128 	ip_print(ndo, (const u_char *)ip, length);
    129 
    130 	return (SLIP_HDRLEN);
    131 }
    132 
    133 static int
    134 sliplink_print(netdissect_options *ndo,
    135                register const u_char *p, register const struct ip *ip,
    136                register u_int length)
    137 {
    138 	int dir;
    139 	u_int hlen;
    140 
    141 	dir = p[SLX_DIR];
    142 	switch (dir) {
    143 
    144 	case SLIPDIR_IN:
    145 		ND_PRINT((ndo, "I "));
    146 		break;
    147 
    148 	case SLIPDIR_OUT:
    149 		ND_PRINT((ndo, "O "));
    150 		break;
    151 
    152 	default:
    153 		ND_PRINT((ndo, "Invalid direction %d ", dir));
    154 		dir = -1;
    155 		break;
    156 	}
    157 	if (ndo->ndo_nflag) {
    158 		/* XXX just dump the header */
    159 		register int i;
    160 
    161 		for (i = SLX_CHDR; i < SLX_CHDR + CHDR_LEN - 1; ++i)
    162 			ND_PRINT((ndo, "%02x.", p[i]));
    163 		ND_PRINT((ndo, "%02x: ", p[SLX_CHDR + CHDR_LEN - 1]));
    164 		return 0;
    165 	}
    166 	switch (p[SLX_CHDR] & 0xf0) {
    167 
    168 	case TYPE_IP:
    169 		ND_PRINT((ndo, "ip %d: ", length + SLIP_HDRLEN));
    170 		break;
    171 
    172 	case TYPE_UNCOMPRESSED_TCP:
    173 		/*
    174 		 * The connection id is stored in the IP protocol field.
    175 		 * Get it from the link layer since sl_uncompress_tcp()
    176 		 * has restored the IP header copy to IPPROTO_TCP.
    177 		 */
    178 		lastconn = ((const struct ip *)&p[SLX_CHDR])->ip_p;
    179 		ND_PRINT((ndo, "utcp %d: ", lastconn));
    180 		if (dir == -1) {
    181 			/* Direction is bogus, don't use it */
    182 			return 0;
    183 		}
    184 		ND_TCHECK(*ip);
    185 		hlen = IP_HL(ip);
    186 		ND_TCHECK(*((const struct tcphdr *)&((const int *)ip)[hlen]));
    187 		hlen += TH_OFF((const struct tcphdr *)&((const int *)ip)[hlen]);
    188 		lastlen[dir][lastconn] = length - (hlen << 2);
    189 		break;
    190 
    191 	default:
    192 		if (dir == -1) {
    193 			/* Direction is bogus, don't use it */
    194 			return 0;
    195 		}
    196 		if (p[SLX_CHDR] & TYPE_COMPRESSED_TCP) {
    197 			if (compressed_sl_print(ndo, &p[SLX_CHDR], ip,
    198 						length, dir) == -1)
    199 				goto trunc;
    200 			ND_PRINT((ndo, ": "));
    201 		} else
    202 			ND_PRINT((ndo, "slip-%d!: ", p[SLX_CHDR]));
    203 	}
    204 	return 0;
    205 trunc:
    206 	return -1;
    207 }
    208 
    209 static const u_char *
    210 print_sl_change(netdissect_options *ndo,
    211                 const char *str, register const u_char *cp)
    212 {
    213 	register u_int i;
    214 
    215 	if ((i = *cp++) == 0) {
    216 		i = EXTRACT_16BITS(cp);
    217 		cp += 2;
    218 	}
    219 	ND_PRINT((ndo, " %s%d", str, i));
    220 	return (cp);
    221 }
    222 
    223 static const u_char *
    224 print_sl_winchange(netdissect_options *ndo,
    225                    register const u_char *cp)
    226 {
    227 	register short i;
    228 
    229 	if ((i = *cp++) == 0) {
    230 		i = EXTRACT_16BITS(cp);
    231 		cp += 2;
    232 	}
    233 	if (i >= 0)
    234 		ND_PRINT((ndo, " W+%d", i));
    235 	else
    236 		ND_PRINT((ndo, " W%d", i));
    237 	return (cp);
    238 }
    239 
    240 static int
    241 compressed_sl_print(netdissect_options *ndo,
    242                     const u_char *chdr, const struct ip *ip,
    243                     u_int length, int dir)
    244 {
    245 	register const u_char *cp = chdr;
    246 	register u_int flags, hlen;
    247 
    248 	flags = *cp++;
    249 	if (flags & NEW_C) {
    250 		lastconn = *cp++;
    251 		ND_PRINT((ndo, "ctcp %d", lastconn));
    252 	} else
    253 		ND_PRINT((ndo, "ctcp *"));
    254 
    255 	/* skip tcp checksum */
    256 	cp += 2;
    257 
    258 	switch (flags & SPECIALS_MASK) {
    259 	case SPECIAL_I:
    260 		ND_PRINT((ndo, " *SA+%d", lastlen[dir][lastconn]));
    261 		break;
    262 
    263 	case SPECIAL_D:
    264 		ND_PRINT((ndo, " *S+%d", lastlen[dir][lastconn]));
    265 		break;
    266 
    267 	default:
    268 		if (flags & NEW_U)
    269 			cp = print_sl_change(ndo, "U=", cp);
    270 		if (flags & NEW_W)
    271 			cp = print_sl_winchange(ndo, cp);
    272 		if (flags & NEW_A)
    273 			cp = print_sl_change(ndo, "A+", cp);
    274 		if (flags & NEW_S)
    275 			cp = print_sl_change(ndo, "S+", cp);
    276 		break;
    277 	}
    278 	if (flags & NEW_I)
    279 		cp = print_sl_change(ndo, "I+", cp);
    280 
    281 	/*
    282 	 * 'hlen' is the length of the uncompressed TCP/IP header (in words).
    283 	 * 'cp - chdr' is the length of the compressed header.
    284 	 * 'length - hlen' is the amount of data in the packet.
    285 	 */
    286 	ND_TCHECK(*ip);
    287 	hlen = IP_HL(ip);
    288 	ND_TCHECK(*((const struct tcphdr *)&((const int32_t *)ip)[hlen]));
    289 	hlen += TH_OFF((const struct tcphdr *)&((const int32_t *)ip)[hlen]);
    290 	lastlen[dir][lastconn] = length - (hlen << 2);
    291 	ND_PRINT((ndo, " %d (%ld)", lastlen[dir][lastconn], (long)(cp - chdr)));
    292 	return 0;
    293 trunc:
    294 	return -1;
    295 }
    296