Home | History | Annotate | Line # | Download | only in dist
print-sl.c revision 1.6
      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.6 2017/01/24 23:29:14 christos Exp $");
     25 #endif
     26 
     27 #ifdef HAVE_CONFIG_H
     28 #include "config.h"
     29 #endif
     30 
     31 #include <netdissect-stdinc.h>
     32 
     33 #include "netdissect.h"
     34 #include "extract.h"
     35 
     36 #include "ip.h"
     37 #include "tcp.h"
     38 #include "slcompress.h"
     39 
     40 /*
     41  * definitions of the pseudo- link-level header attached to slip
     42  * packets grabbed by the packet filter (bpf) traffic monitor.
     43  */
     44 #define SLIP_HDRLEN 16
     45 
     46 #define SLX_DIR 0
     47 #define SLX_CHDR 1
     48 #define CHDR_LEN 15
     49 
     50 #define SLIPDIR_IN 0
     51 #define SLIPDIR_OUT 1
     52 
     53 static const char tstr[] = "[|slip]";
     54 
     55 static u_int lastlen[2][256];
     56 static u_int lastconn = 255;
     57 
     58 static void sliplink_print(netdissect_options *, const u_char *, const struct ip *, u_int);
     59 static void compressed_sl_print(netdissect_options *, const u_char *, const struct ip *, u_int, int);
     60 
     61 u_int
     62 sl_if_print(netdissect_options *ndo,
     63             const struct pcap_pkthdr *h, const u_char *p)
     64 {
     65 	register u_int caplen = h->caplen;
     66 	register u_int length = h->len;
     67 	register const struct ip *ip;
     68 
     69 	if (caplen < SLIP_HDRLEN || length < SLIP_HDRLEN) {
     70 		ND_PRINT((ndo, "%s", tstr));
     71 		return (caplen);
     72 	}
     73 
     74 	length -= SLIP_HDRLEN;
     75 
     76 	ip = (const struct ip *)(p + SLIP_HDRLEN);
     77 
     78 	if (ndo->ndo_eflag)
     79 		sliplink_print(ndo, p, ip, length);
     80 
     81 	switch (IP_V(ip)) {
     82 	case 4:
     83 	        ip_print(ndo, (const u_char *)ip, length);
     84 		break;
     85 	case 6:
     86 		ip6_print(ndo, (const u_char *)ip, length);
     87 		break;
     88 	default:
     89 		ND_PRINT((ndo, "ip v%d", IP_V(ip)));
     90 	}
     91 
     92 	return (SLIP_HDRLEN);
     93 }
     94 
     95 u_int
     96 sl_bsdos_if_print(netdissect_options *ndo,
     97                   const struct pcap_pkthdr *h, const u_char *p)
     98 {
     99 	register u_int caplen = h->caplen;
    100 	register u_int length = h->len;
    101 	register const struct ip *ip;
    102 
    103 	if (caplen < SLIP_HDRLEN) {
    104 		ND_PRINT((ndo, "%s", tstr));
    105 		return (caplen);
    106 	}
    107 
    108 	length -= SLIP_HDRLEN;
    109 
    110 	ip = (const struct ip *)(p + SLIP_HDRLEN);
    111 
    112 #ifdef notdef
    113 	if (ndo->ndo_eflag)
    114 		sliplink_print(ndo, p, ip, length);
    115 #endif
    116 
    117 	ip_print(ndo, (const u_char *)ip, length);
    118 
    119 	return (SLIP_HDRLEN);
    120 }
    121 
    122 static void
    123 sliplink_print(netdissect_options *ndo,
    124                register const u_char *p, register const struct ip *ip,
    125                register u_int length)
    126 {
    127 	int dir;
    128 	u_int hlen;
    129 
    130 	dir = p[SLX_DIR];
    131 	ND_PRINT((ndo, dir == SLIPDIR_IN ? "I " : "O "));
    132 
    133 	if (ndo->ndo_nflag) {
    134 		/* XXX just dump the header */
    135 		register int i;
    136 
    137 		for (i = SLX_CHDR; i < SLX_CHDR + CHDR_LEN - 1; ++i)
    138 			ND_PRINT((ndo, "%02x.", p[i]));
    139 		ND_PRINT((ndo, "%02x: ", p[SLX_CHDR + CHDR_LEN - 1]));
    140 		return;
    141 	}
    142 	switch (p[SLX_CHDR] & 0xf0) {
    143 
    144 	case TYPE_IP:
    145 		ND_PRINT((ndo, "ip %d: ", length + SLIP_HDRLEN));
    146 		break;
    147 
    148 	case TYPE_UNCOMPRESSED_TCP:
    149 		/*
    150 		 * The connection id is stored in the IP protocol field.
    151 		 * Get it from the link layer since sl_uncompress_tcp()
    152 		 * has restored the IP header copy to IPPROTO_TCP.
    153 		 */
    154 		lastconn = ((const struct ip *)&p[SLX_CHDR])->ip_p;
    155 		hlen = IP_HL(ip);
    156 		hlen += TH_OFF((const struct tcphdr *)&((const int *)ip)[hlen]);
    157 		lastlen[dir][lastconn] = length - (hlen << 2);
    158 		ND_PRINT((ndo, "utcp %d: ", lastconn));
    159 		break;
    160 
    161 	default:
    162 		if (p[SLX_CHDR] & TYPE_COMPRESSED_TCP) {
    163 			compressed_sl_print(ndo, &p[SLX_CHDR], ip,
    164 			    length, dir);
    165 			ND_PRINT((ndo, ": "));
    166 		} else
    167 			ND_PRINT((ndo, "slip-%d!: ", p[SLX_CHDR]));
    168 	}
    169 }
    170 
    171 static const u_char *
    172 print_sl_change(netdissect_options *ndo,
    173                 const char *str, register const u_char *cp)
    174 {
    175 	register u_int i;
    176 
    177 	if ((i = *cp++) == 0) {
    178 		i = EXTRACT_16BITS(cp);
    179 		cp += 2;
    180 	}
    181 	ND_PRINT((ndo, " %s%d", str, i));
    182 	return (cp);
    183 }
    184 
    185 static const u_char *
    186 print_sl_winchange(netdissect_options *ndo,
    187                    register const u_char *cp)
    188 {
    189 	register short i;
    190 
    191 	if ((i = *cp++) == 0) {
    192 		i = EXTRACT_16BITS(cp);
    193 		cp += 2;
    194 	}
    195 	if (i >= 0)
    196 		ND_PRINT((ndo, " W+%d", i));
    197 	else
    198 		ND_PRINT((ndo, " W%d", i));
    199 	return (cp);
    200 }
    201 
    202 static void
    203 compressed_sl_print(netdissect_options *ndo,
    204                     const u_char *chdr, const struct ip *ip,
    205                     u_int length, int dir)
    206 {
    207 	register const u_char *cp = chdr;
    208 	register u_int flags, hlen;
    209 
    210 	flags = *cp++;
    211 	if (flags & NEW_C) {
    212 		lastconn = *cp++;
    213 		ND_PRINT((ndo, "ctcp %d", lastconn));
    214 	} else
    215 		ND_PRINT((ndo, "ctcp *"));
    216 
    217 	/* skip tcp checksum */
    218 	cp += 2;
    219 
    220 	switch (flags & SPECIALS_MASK) {
    221 	case SPECIAL_I:
    222 		ND_PRINT((ndo, " *SA+%d", lastlen[dir][lastconn]));
    223 		break;
    224 
    225 	case SPECIAL_D:
    226 		ND_PRINT((ndo, " *S+%d", lastlen[dir][lastconn]));
    227 		break;
    228 
    229 	default:
    230 		if (flags & NEW_U)
    231 			cp = print_sl_change(ndo, "U=", cp);
    232 		if (flags & NEW_W)
    233 			cp = print_sl_winchange(ndo, cp);
    234 		if (flags & NEW_A)
    235 			cp = print_sl_change(ndo, "A+", cp);
    236 		if (flags & NEW_S)
    237 			cp = print_sl_change(ndo, "S+", cp);
    238 		break;
    239 	}
    240 	if (flags & NEW_I)
    241 		cp = print_sl_change(ndo, "I+", cp);
    242 
    243 	/*
    244 	 * 'hlen' is the length of the uncompressed TCP/IP header (in words).
    245 	 * 'cp - chdr' is the length of the compressed header.
    246 	 * 'length - hlen' is the amount of data in the packet.
    247 	 */
    248 	hlen = IP_HL(ip);
    249 	hlen += TH_OFF((const struct tcphdr *)&((const int32_t *)ip)[hlen]);
    250 	lastlen[dir][lastconn] = length - (hlen << 2);
    251 	ND_PRINT((ndo, " %d (%ld)", lastlen[dir][lastconn], (long)(cp - chdr)));
    252 }
    253