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