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