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