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