1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <string.h> 31 #include <sys/types.h> 32 #include <sys/socket.h> 33 #include <sys/sysmacros.h> 34 #include <netinet/in.h> 35 #include <arpa/inet.h> 36 #include <net/pppoe.h> 37 #include "snoop.h" 38 39 /* 40 * These two macros extract the version and type fields respectively from 41 * the first byte of the PPPoE header. 42 */ 43 #define POE_VERS(x) (((x) >> 4) & 0x0f) 44 #define POE_TYPE(x) ((x) & 0x0f) 45 46 typedef void interpret_func_t(uint8_t *, uint16_t); 47 48 typedef struct taginfo { 49 char *tag_name; 50 uint16_t tag_type; 51 interpret_func_t *interpret_tagvalue; 52 } taginfo_t; 53 54 55 static char *pppoe_codetoname(int, boolean_t); 56 static taginfo_t *pppoe_gettaginfo(uint16_t); 57 static void print_hexdata(char *, uint8_t *, uint16_t); 58 static void print_utf8string(char *, char *, uint16_t); 59 static char *print_linetag(char *); 60 static interpret_func_t interpret_tags; 61 static interpret_func_t interpret_hexdata; 62 static interpret_func_t interpret_service; 63 static interpret_func_t interpret_access; 64 static interpret_func_t interpret_cookie; 65 static interpret_func_t interpret_vendor; 66 static interpret_func_t interpret_relay; 67 static interpret_func_t interpret_error; 68 static interpret_func_t interpret_hurl; 69 static interpret_func_t interpret_motm; 70 static interpret_func_t interpret_rteadd; 71 72 73 static taginfo_t taginfo_array[] = { 74 { "End-Of-List", POETT_END, interpret_hexdata }, 75 { "Service-Name", POETT_SERVICE, interpret_service }, 76 { "AC-Name", POETT_ACCESS, interpret_access }, 77 { "Host-Uniq", POETT_UNIQ, interpret_hexdata }, 78 { "AC-Cookie", POETT_COOKIE, interpret_cookie }, 79 { "Vendor-Specific", POETT_VENDOR, interpret_vendor }, 80 { "Relay-Session-Id", POETT_RELAY, interpret_relay }, 81 { "Service-Name-Error", POETT_NAMERR, interpret_error }, 82 { "AC-System-Error", POETT_SYSERR, interpret_error }, 83 { "Generic-Error", POETT_GENERR, interpret_error }, 84 { "Multicast-Capable", POETT_MULTI, interpret_hexdata }, 85 { "Host-URL", POETT_HURL, interpret_hurl }, 86 { "Message-Of-The-Minute", POETT_MOTM, interpret_motm }, 87 { "IP-Route-Add", POETT_RTEADD, interpret_rteadd }, 88 { "Unknown TAG", 0, NULL } 89 }; 90 91 92 int 93 interpret_pppoe(int flags, poep_t *poep, int len) 94 { 95 uint8_t code = poep->poep_code; 96 uint8_t *payload; 97 98 if (len < sizeof (poep_t)) 99 return (len); 100 101 payload = (uint8_t *)poep + sizeof (poep_t); 102 103 if (flags & F_SUM) { 104 (void) sprintf(get_sum_line(), "PPPoE %s", 105 pppoe_codetoname(code, B_FALSE)); 106 } else { /* flags & F_DTAIL */ 107 show_header("PPPoE: ", "PPP Over Ethernet", len); 108 show_space(); 109 110 (void) sprintf(get_line(0, 0), 111 "Version = %d", POE_VERS(poep->poep_version_type)); 112 113 (void) sprintf(get_line(0, 0), 114 "Type = %d", POE_TYPE(poep->poep_version_type)); 115 116 (void) sprintf(get_line(0, 0), 117 "Code = %d (%s)", code, pppoe_codetoname(code, B_TRUE)); 118 119 (void) sprintf(get_line(0, 0), 120 "Session Id = %d", ntohs(poep->poep_session_id)); 121 122 (void) sprintf(get_line(0, 0), 123 "Length = %d bytes", ntohs(poep->poep_length)); 124 125 show_space(); 126 127 len -= sizeof (poep_t); 128 len = MIN(len, ntohs(poep->poep_length)); 129 130 if (poep->poep_code != 0 && poep->poep_length > 0) { 131 interpret_tags(payload, len); 132 } 133 } 134 135 if (poep->poep_code == 0) { 136 return (interpret_ppp(flags, payload, len)); 137 } 138 return (len); 139 } 140 141 142 /* 143 * interpret_tags() prints PPPoE Discovery Stage TAGs in detail. 144 */ 145 static void 146 interpret_tags(uint8_t *payload, uint16_t length) 147 { 148 uint8_t *tagptr = payload; 149 uint16_t tag_length; 150 uint16_t tag_type; 151 uint8_t *tag_value; 152 taginfo_t *tinfo; 153 154 while (length >= POET_HDRLEN) { 155 tag_type = POET_GET_TYPE(tagptr); 156 tag_length = POET_GET_LENG(tagptr); 157 158 tinfo = pppoe_gettaginfo(tag_type); 159 160 show_header("PPPoE: ", tinfo->tag_name, 161 tag_length + POET_HDRLEN); 162 163 (void) sprintf(get_line(0, 0), 164 "Tag Type = %d", tag_type); 165 166 (void) sprintf(get_line(0, 0), 167 "Tag Length = %d bytes", tag_length); 168 169 length -= POET_HDRLEN; 170 if (tag_length > length) { 171 (void) sprintf(get_line(0, 0), 172 "Warning: Truncated Packet"); 173 show_space(); 174 break; 175 } 176 177 /* 178 * unknown tags or tags which should always have 0 length 179 * are not interpreted any further. 180 */ 181 tag_value = POET_DATA(tagptr); 182 if (tag_length != 0 && tinfo->interpret_tagvalue != NULL) 183 tinfo->interpret_tagvalue(tag_value, tag_length); 184 185 show_space(); 186 length -= tag_length; 187 tagptr = POET_NEXT(tagptr); 188 } 189 } 190 191 static char * 192 pppoe_codetoname(int code, boolean_t verbose) 193 { 194 char *name; 195 196 switch (code) { 197 case POECODE_DATA: 198 name = "Session"; 199 break; 200 case POECODE_PADO: 201 if (verbose) 202 name = "Active Discovery Offer"; 203 else 204 name = "PADO"; 205 break; 206 case POECODE_PADI: 207 if (verbose) 208 name = "Active Discovery Initiation"; 209 else 210 name = "PADI"; 211 break; 212 case POECODE_PADR: 213 if (verbose) 214 name = "Active Discovery Request"; 215 else 216 name = "PADR"; 217 break; 218 case POECODE_PADS: 219 if (verbose) 220 name = "Active Discovery Session-Confirmation"; 221 else 222 name = "PADS"; 223 break; 224 case POECODE_PADT: 225 if (verbose) 226 name = "Active Discovery Terminate"; 227 else 228 name = "PADT"; 229 break; 230 case POECODE_PADM: 231 if (verbose) 232 name = "Active Discovery Message"; 233 else 234 name = "PADM"; 235 break; 236 case POECODE_PADN: 237 if (verbose) 238 name = "Active Discovery Network"; 239 else 240 name = "PADN"; 241 break; 242 default: 243 name = "Unknown Code"; 244 } 245 246 return (name); 247 } 248 249 static taginfo_t * 250 pppoe_gettaginfo(uint16_t type) 251 { 252 taginfo_t *taginfo_ptr = &taginfo_array[0]; 253 int i = 0; 254 255 while (taginfo_ptr->tag_type != type && 256 taginfo_ptr->interpret_tagvalue != NULL) { 257 taginfo_ptr = &taginfo_array[++i]; 258 } 259 260 return (taginfo_ptr); 261 } 262 263 static void 264 interpret_hexdata(uint8_t *tag_value, uint16_t tag_length) 265 { 266 char *endofline; 267 268 endofline = print_linetag("Data = "); 269 print_hexdata(endofline, tag_value, tag_length); 270 } 271 272 static void 273 interpret_service(uint8_t *tag_value, uint16_t tag_length) 274 { 275 char *endofline; 276 277 endofline = print_linetag("Service Name = "); 278 print_utf8string(endofline, (char *)tag_value, tag_length); 279 } 280 281 static void 282 interpret_access(uint8_t *tag_value, uint16_t tag_length) 283 { 284 char *endofline; 285 286 endofline = print_linetag("AC Name = "); 287 print_utf8string(endofline, (char *)tag_value, tag_length); 288 } 289 290 static void 291 interpret_cookie(uint8_t *tag_value, uint16_t tag_length) 292 { 293 char *endofline; 294 295 endofline = print_linetag("Cookie = "); 296 print_hexdata(endofline, tag_value, tag_length); 297 } 298 299 static void 300 interpret_vendor(uint8_t *tag_value, uint16_t tag_length) 301 { 302 uint8_t *vendor_data; 303 uint32_t vendorid; 304 char *endofline; 305 306 vendorid = ntohl(*(uint32_t *)tag_value); 307 (void) sprintf(get_line(0, 0), 308 "Vendor ID = %d", vendorid); 309 310 if (tag_length > 4) { 311 vendor_data = tag_value + 4; 312 endofline = print_linetag("Vendor Data = "); 313 print_hexdata(endofline, vendor_data, tag_length - 4); 314 } 315 } 316 317 static void 318 interpret_relay(uint8_t *tag_value, uint16_t tag_length) 319 { 320 char *endofline; 321 322 endofline = print_linetag("ID = "); 323 print_hexdata(endofline, tag_value, tag_length); 324 } 325 326 static void 327 interpret_error(uint8_t *tag_value, uint16_t tag_length) 328 { 329 char *endofline; 330 331 endofline = print_linetag("Error = "); 332 print_utf8string(endofline, (char *)tag_value, tag_length); 333 } 334 335 static void 336 interpret_hurl(uint8_t *tag_value, uint16_t tag_length) 337 { 338 char *endofline; 339 340 endofline = print_linetag("URL = "); 341 print_utf8string(endofline, (char *)tag_value, tag_length); 342 } 343 344 static void 345 interpret_motm(uint8_t *tag_value, uint16_t tag_length) 346 { 347 char *endofline; 348 349 endofline = print_linetag("Message = "); 350 print_utf8string(endofline, (char *)tag_value, tag_length); 351 } 352 353 static void 354 interpret_rteadd(uint8_t *tag_value, uint16_t tag_length) 355 { 356 char dest[INET_ADDRSTRLEN]; 357 char mask[INET_ADDRSTRLEN]; 358 char gateway[INET_ADDRSTRLEN]; 359 uint32_t metric; 360 361 if (tag_length == 16) { 362 (void) inet_ntop(AF_INET, tag_value, dest, 363 INET_ADDRSTRLEN); 364 (void) inet_ntop(AF_INET, &tag_value[4], mask, 365 INET_ADDRSTRLEN); 366 (void) inet_ntop(AF_INET, &tag_value[8], gateway, 367 INET_ADDRSTRLEN); 368 metric = ntohl(*(uint32_t *)&tag_value[12]); 369 sprintf(get_line(0, 0), 370 "Destination\tNetmask\tGateway\tMetric"); 371 sprintf(get_line(0, 0), 372 "%s\t%s\t%s\t%d", dest, mask, gateway, metric); 373 } 374 } 375 376 static void 377 print_hexdata(char *line, uint8_t *data, uint16_t length) 378 { 379 uint16_t index = 0; 380 381 line += sprintf(line, "0x"); 382 383 while (index < length) { 384 line += sprintf(line, "%02x", data[index++]); 385 } 386 } 387 388 static void 389 print_utf8string(char *firstline, char *string, uint16_t length) 390 { 391 (void) sprintf(firstline, "%.*s", length, string); 392 } 393 394 static char * 395 print_linetag(char *string) 396 { 397 char *line = get_line(0, 0); 398 return (line + sprintf(line, string)); 399 } 400